mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-03-19 17:30:27 +08:00
move from oc1.0 to oc2.0; create new dir oc2
This commit is contained in:
parent
59960fcc20
commit
42999f4c7c
2
INSTALL
2
INSTALL
@ -2,7 +2,7 @@ Documentation for getting and building netCDF
|
||||
*********************************************
|
||||
|
||||
This document is for getting and building the netCDF C library and
|
||||
utilities, version 4.2.1. Other libraries that depend on the netCDF C
|
||||
utilities, version 4.3. Other libraries that depend on the netCDF C
|
||||
library, such as the Fortran and C++ libraries, are available as
|
||||
separate distributions that can be built and installed after the C
|
||||
library is successfully installed. The netCDF-Java library is also a
|
||||
|
@ -49,7 +49,7 @@ endif
|
||||
|
||||
# Build the opendap client?
|
||||
if BUILD_DAP
|
||||
OCLIB = oc
|
||||
OCLIB = oc2
|
||||
DAP2 = libdap2
|
||||
#if BUILD_UTILITIES
|
||||
NCDAPTESTDIR = ncdap_test
|
||||
|
@ -6,6 +6,11 @@ https://www.unidata.ucar.edu/jira/browse/NCF-XXX .
|
||||
|
||||
VERSION COMMENTS
|
||||
------- --------
|
||||
4.3 Released 201?-??-??
|
||||
|
||||
Replaced the oc library with oc2.0
|
||||
|
||||
|
||||
4.2.1 Released 2012-07-18
|
||||
|
||||
Added a specific NC_MMAP mode flag to modify
|
||||
|
8
cf
8
cf
@ -52,7 +52,6 @@ LD_LIBRARY_PATH="/usr/local/pgi/linux86-64/11.1/lib:$LD_LIBRARY_PATH"
|
||||
PREFIX=/tmp/install/pgi
|
||||
fi
|
||||
|
||||
|
||||
if test x$M32 = x1 ; then
|
||||
PREFIX="/tmp/install32/${HOST}"
|
||||
stddir="/share/ed/local/${HOST}_32"
|
||||
@ -63,12 +62,19 @@ elif test x$M64 = x1 ; then
|
||||
CFLAGS="-m64 $CFLAGS"
|
||||
fi
|
||||
|
||||
if test "x$HOST" = xyakov ; then
|
||||
stddir="/opt/local"
|
||||
fi
|
||||
|
||||
CFLAGS="-g -O0 $CFLAGS"
|
||||
|
||||
case "$HOST" in
|
||||
mort)
|
||||
CFLAGS="-std=c99 $CFLAGS"
|
||||
;;
|
||||
yakov)
|
||||
CFLAGS="-std=c99 $CFLAGS"
|
||||
;;
|
||||
spock)
|
||||
if test "x$PGI" = x ; then
|
||||
CFLAGS="-Wdeclaration-after-statement -Wall $CFLAGS"
|
||||
|
@ -15,7 +15,7 @@ AC_REVISION([$Id: configure.ac,v 1.450 2010/05/28 19:42:47 dmh Exp $])
|
||||
AC_PREREQ([2.59])
|
||||
|
||||
# Initialize with name, version, and support email address.
|
||||
AC_INIT([netCDF], [4.2.1], [support-netcdf@unidata.ucar.edu])
|
||||
AC_INIT([netCDF], [4.3], [support-netcdf@unidata.ucar.edu])
|
||||
|
||||
# Create the VERSION file, which contains the package version from
|
||||
# AC_INIT.
|
||||
@ -803,7 +803,7 @@ BINFILE_NAME=${BINFILE_NAME}.tar
|
||||
AC_SUBST(BINFILE_NAME)
|
||||
AC_MSG_RESULT([$BINFILE_NAME $FC $CXX])
|
||||
|
||||
UD_FTPBINDIR
|
||||
#UD_FTPBINDIR
|
||||
|
||||
AC_MSG_CHECKING([value of LIBS])
|
||||
AC_MSG_RESULT([$LIBS])
|
||||
@ -875,7 +875,7 @@ AC_CONFIG_FILES([Makefile
|
||||
examples/Makefile
|
||||
examples/C/Makefile
|
||||
examples/CDL/Makefile
|
||||
oc/Makefile
|
||||
oc2/Makefile
|
||||
libdap2/Makefile
|
||||
libcdmr/Makefile
|
||||
librpc/Makefile
|
||||
|
@ -42,7 +42,7 @@ EXTERNC int ncbytesappendn(NCbytes*,void*,unsigned int); /* Add at Tail */
|
||||
EXTERNC int ncbytesnull(NCbytes*);
|
||||
|
||||
/* Concatenate a null-terminated string to the end of the buffer */
|
||||
EXTERNC int ncbytescat(NCbytes*,char*);
|
||||
EXTERNC int ncbytescat(NCbytes*,const char*);
|
||||
|
||||
/* Set the contents of the buffer; mark the buffer as non-extendible */
|
||||
EXTERNC int ncbytessetcontents(NCbytes*, char*, unsigned int);
|
||||
|
@ -49,7 +49,6 @@ EXTERNC int nclistcontains(NClist*, ncelem);
|
||||
/* Remove element by value; only removes first encountered */
|
||||
EXTERNC int nclistelemremove(NClist* l, ncelem elem);
|
||||
|
||||
|
||||
/* remove duplicates */
|
||||
EXTERNC int nclistunique(NClist*);
|
||||
|
||||
|
@ -330,7 +330,7 @@ by the desired type. */
|
||||
#define NC_EDDS (-72) /**< Malformed or inaccessible DDS */
|
||||
#define NC_EDATADDS (-73) /**< Malformed or inaccessible DATADDS */
|
||||
#define NC_EDAPURL (-74) /**< Malformed DAP URL */
|
||||
#define NC_EDAPCONSTRAINT (-75) /**< Malformed DAP Constraint*/
|
||||
#define NC_EDAPCONSTRAINT (-75) /**< Malformed DAP Constraint*/
|
||||
#define NC_ETRANSLATION (-76) /**< Untranslatable construct */
|
||||
|
||||
/* The following was added in support of netcdf-4. Make all netcdf-4
|
||||
|
@ -10,7 +10,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_LDFLAGS =
|
||||
|
||||
if USE_DAP
|
||||
AM_CPPFLAGS += -I${top_srcdir}/oc
|
||||
AM_CPPFLAGS += -I${top_srcdir}/oc2
|
||||
endif
|
||||
|
||||
# This turns on declspec magic in netcdf.h for windows DLLs.
|
||||
|
@ -33,8 +33,8 @@ RPATH=-Wl,-rpath,${LFLAG}
|
||||
|
||||
# Might want to specify a particular C compiler with flags
|
||||
CC=cc
|
||||
CFLAGS=-g -O2 -Wall -DHAVE_CONFIG_H
|
||||
#CFLAGS=-DHAVE_CONFIG_H
|
||||
#CFLAGS=-g -O2 -Wall -DHAVE_CONFIG_H
|
||||
CFLAGS=-g -O2 -DHAVE_CONFIG_H
|
||||
|
||||
GFLAGS=-g3 -O0
|
||||
#############################################
|
||||
|
@ -46,7 +46,7 @@ libdap2_la_LIBADD =
|
||||
#endif
|
||||
#
|
||||
#LDADD += ${top_builddir}/libsrc/libnetcdf3.la \
|
||||
# ${top_builddir}/oc/liboc.la \
|
||||
# ${top_builddir}/oc2/liboc.la \
|
||||
# ${top_builddir}/libdispatch/libdispatch.la
|
||||
#
|
||||
endif # BUILD_DAP
|
||||
|
@ -4,7 +4,6 @@
|
||||
* $Header$
|
||||
*********************************************************************/
|
||||
#include "ncdap3.h"
|
||||
#include "dapodom.h"
|
||||
#include "dapdump.h"
|
||||
|
||||
static int iscacheableconstraint(DCEconstraint* con);
|
||||
@ -80,7 +79,8 @@ else
|
||||
/* Compute the set of prefetched data.
|
||||
Notes:
|
||||
1. Even if caching is off, we will
|
||||
still prefetch the small variables.
|
||||
still prefetch the small variables,
|
||||
unless prefetch is specifically disabled.
|
||||
2. All prefetches are whole variable fetches.
|
||||
3. If the data set is unconstrainable, we
|
||||
will prefetch the whole thing
|
||||
@ -97,7 +97,6 @@ prefetchdata3(NCDAPCOMMON* nccomm)
|
||||
DCEconstraint* newconstraint = NULL;
|
||||
int isnc4 = FLAGSET(nccomm->controls,NCF_NC4);
|
||||
|
||||
|
||||
if(FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) {
|
||||
/* If we cannot constrain and caching is enabled,
|
||||
then pull in everything */
|
||||
@ -109,12 +108,18 @@ prefetchdata3(NCDAPCOMMON* nccomm)
|
||||
nccomm->cdf.cache->prefetch = NULL;
|
||||
goto done;
|
||||
}
|
||||
} else { /* can do constraints */
|
||||
} else { /* can use projections to get subset of variables */
|
||||
/* pull in those variables of sufficiently small size */
|
||||
for(i=0;i<nclistlength(allvars);i++) {
|
||||
CDFnode* var = (CDFnode*)nclistget(allvars,i);
|
||||
size_t nelems = 1;
|
||||
|
||||
/* Do not attempt to prefetch any variables in the
|
||||
nc_open url's projection list
|
||||
*/
|
||||
if(nclistcontains(nccomm->cdf.projectedvars,(ncelem)var))
|
||||
continue;
|
||||
|
||||
if(!isnc4) {
|
||||
/* If netcdf 3 and var is a sequence or under a sequence, then never prefetch */
|
||||
if(var->nctype == NC_Sequence || dapinsequence(var)) continue;
|
||||
@ -207,8 +212,8 @@ buildcachenode34(NCDAPCOMMON* nccomm,
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCconnection conn = nccomm->oc.conn;
|
||||
OCobject ocroot = OCNULL;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
OCddsnode ocroot = NULL;
|
||||
CDFnode* dxdroot = NULL;
|
||||
NCcachenode* cachenode = NULL;
|
||||
char* ce = NULL;
|
||||
@ -240,8 +245,7 @@ buildcachenode34(NCDAPCOMMON* nccomm,
|
||||
|
||||
/* save the root content*/
|
||||
cachenode->ocroot = ocroot;
|
||||
cachenode->content = oc_data_new(conn);
|
||||
ocstat = oc_data_root(conn,ocroot,cachenode->content);
|
||||
ocstat = oc_data_getroot(conn,ocroot,&cachenode->content);
|
||||
if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;}
|
||||
|
||||
/* capture the packet size */
|
||||
@ -310,6 +314,10 @@ void
|
||||
freenccachenode(NCDAPCOMMON* nccomm, NCcachenode* node)
|
||||
{
|
||||
if(node == NULL) return;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"freecachenode: %s\n",
|
||||
dumpcachenode(node));
|
||||
#endif
|
||||
oc_data_free(nccomm->oc.conn,node->content);
|
||||
dcefree((DCEnode*)node->constraint);
|
||||
freecdfroot34(node->datadds);
|
||||
|
@ -70,7 +70,7 @@ computevarnodes3(NCDAPCOMMON* nccomm, NClist* allnodes, NClist* varnodes)
|
||||
node->ocname = newname;
|
||||
}
|
||||
if(!node->visible) continue;
|
||||
if(node->nctype == NC_Primitive)
|
||||
if(node->nctype == NC_Atomic)
|
||||
nclistpush(allvarnodes,(ncelem)node);
|
||||
}
|
||||
/* Further process the variable nodes to get the final set */
|
||||
@ -658,7 +658,7 @@ clonedim(NCDAPCOMMON* nccomm, CDFnode* dim, CDFnode* var)
|
||||
{
|
||||
CDFnode* clone;
|
||||
clone = makecdfnode34(nccomm,dim->ocname,OC_Dimension,
|
||||
OCNULL,dim->container);
|
||||
NULL,dim->container);
|
||||
/* Record its existence */
|
||||
nclistpush(dim->container->root->tree->nodes,(ncelem)clone);
|
||||
clone->dim = dim->dim; /* copy most everything */
|
||||
|
@ -20,8 +20,8 @@ extern CDFnode* v4node;
|
||||
|
||||
/* Define the set of protocols known to be constrainable */
|
||||
static char* constrainableprotocols[] = {"http", "https",NULL};
|
||||
static NCerror buildcdftree34r(NCDAPCOMMON*,OCobject,CDFnode*,CDFtree*,CDFnode**);
|
||||
static void defdimensions(OCobject, CDFnode*, NCDAPCOMMON*, CDFtree*);
|
||||
static NCerror buildcdftree34r(NCDAPCOMMON*,OCddsnode,CDFnode*,CDFtree*,CDFnode**);
|
||||
static void defdimensions(OCddsnode, CDFnode*, NCDAPCOMMON*, CDFtree*);
|
||||
static NCerror attachsubset34r(CDFnode*, CDFnode*);
|
||||
static void free1cdfnode34(CDFnode* node);
|
||||
|
||||
@ -42,7 +42,7 @@ fix1node34(NCDAPCOMMON* nccomm, CDFnode* node)
|
||||
nullfree(node->ncfullname);
|
||||
node->ncfullname = makecdfpathstring3(node,nccomm->cdf.separator);
|
||||
if(node->ncfullname == NULL) return NC_ENOMEM;
|
||||
if(node->nctype == NC_Primitive)
|
||||
if(node->nctype == NC_Atomic)
|
||||
node->externaltype = nctypeconvert(nccomm,node->etype);
|
||||
return NC_NOERR;
|
||||
}
|
||||
@ -376,7 +376,7 @@ constrainable34(NC_URI* durl)
|
||||
|
||||
CDFnode*
|
||||
makecdfnode34(NCDAPCOMMON* nccomm, char* name, OCtype octype,
|
||||
/*optional*/ OCobject ocnode, CDFnode* container)
|
||||
/*optional*/ OCddsnode ocnode, CDFnode* container)
|
||||
{
|
||||
CDFnode* node;
|
||||
assert(nccomm != NULL);
|
||||
@ -396,8 +396,8 @@ makecdfnode34(NCDAPCOMMON* nccomm, char* name, OCtype octype,
|
||||
node->ocnode = ocnode;
|
||||
node->subnodes = nclistnew();
|
||||
node->container = container;
|
||||
if(ocnode != OCNULL) {
|
||||
oc_inq_primtype(nccomm->oc.conn,ocnode,&octype);
|
||||
if(ocnode != NULL) {
|
||||
oc_dds_atomictype(nccomm->oc.conn,ocnode,&octype);
|
||||
node->etype = octypetonc(octype);
|
||||
}
|
||||
return node;
|
||||
@ -408,7 +408,7 @@ makecdfnode34(NCDAPCOMMON* nccomm, char* name, OCtype octype,
|
||||
of all nodes in preorder.
|
||||
*/
|
||||
NCerror
|
||||
buildcdftree34(NCDAPCOMMON* nccomm, OCobject ocroot, OCdxd occlass, CDFnode** cdfrootp)
|
||||
buildcdftree34(NCDAPCOMMON* nccomm, OCddsnode ocroot, OCdxd occlass, CDFnode** cdfrootp)
|
||||
{
|
||||
CDFnode* root = NULL;
|
||||
CDFtree* tree = (CDFtree*)calloc(1,sizeof(CDFtree));
|
||||
@ -428,26 +428,26 @@ buildcdftree34(NCDAPCOMMON* nccomm, OCobject ocroot, OCdxd occlass, CDFnode** cd
|
||||
}
|
||||
|
||||
static NCerror
|
||||
buildcdftree34r(NCDAPCOMMON* nccomm, OCobject ocnode, CDFnode* container,
|
||||
buildcdftree34r(NCDAPCOMMON* nccomm, OCddsnode ocnode, CDFnode* container,
|
||||
CDFtree* tree, CDFnode** cdfnodep)
|
||||
{
|
||||
unsigned int i,ocrank,ocnsubnodes;
|
||||
size_t i,ocrank,ocnsubnodes;
|
||||
OCtype octype;
|
||||
char* ocname = NULL;
|
||||
NCerror ncerr = NC_NOERR;
|
||||
CDFnode* cdfnode;
|
||||
|
||||
oc_inq_class(nccomm->oc.conn,ocnode,&octype);
|
||||
oc_inq_name(nccomm->oc.conn,ocnode,&ocname);
|
||||
oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank);
|
||||
oc_inq_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes);
|
||||
oc_dds_class(nccomm->oc.conn,ocnode,&octype);
|
||||
oc_dds_name(nccomm->oc.conn,ocnode,&ocname);
|
||||
oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
|
||||
oc_dds_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes);
|
||||
|
||||
switch (octype) {
|
||||
case OC_Dataset:
|
||||
case OC_Grid:
|
||||
case OC_Structure:
|
||||
case OC_Sequence:
|
||||
case OC_Primitive:
|
||||
case OC_Atomic:
|
||||
cdfnode = makecdfnode34(nccomm,ocname,octype,ocnode,container);
|
||||
nclistpush(tree->nodes,(ncelem)cdfnode);
|
||||
if(tree->root == NULL) {
|
||||
@ -465,9 +465,9 @@ buildcdftree34r(NCDAPCOMMON* nccomm, OCobject ocnode, CDFnode* container,
|
||||
|
||||
if(ocrank > 0) defdimensions(ocnode,cdfnode,nccomm,tree);
|
||||
for(i=0;i<ocnsubnodes;i++) {
|
||||
OCobject ocsubnode;
|
||||
OCddsnode ocsubnode;
|
||||
CDFnode* subnode;
|
||||
oc_inq_ith(nccomm->oc.conn,ocnode,i,&ocsubnode);
|
||||
oc_dds_ithfield(nccomm->oc.conn,ocnode,i,&ocsubnode);
|
||||
ncerr = buildcdftree34r(nccomm,ocsubnode,cdfnode,tree,&subnode);
|
||||
if(ncerr) return ncerr;
|
||||
nclistpush(cdfnode->subnodes,(ncelem)subnode);
|
||||
@ -478,20 +478,20 @@ buildcdftree34r(NCDAPCOMMON* nccomm, OCobject ocnode, CDFnode* container,
|
||||
}
|
||||
|
||||
static void
|
||||
defdimensions(OCobject ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree)
|
||||
defdimensions(OCddsnode ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree)
|
||||
{
|
||||
unsigned int i,ocrank;
|
||||
size_t i,ocrank;
|
||||
|
||||
oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank);
|
||||
oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
|
||||
assert(ocrank > 0);
|
||||
for(i=0;i<ocrank;i++) {
|
||||
CDFnode* cdfdim;
|
||||
OCobject ocdim;
|
||||
OCddsnode ocdim;
|
||||
char* ocname;
|
||||
size_t declsize;
|
||||
|
||||
oc_inq_ithdim(nccomm->oc.conn,ocnode,i,&ocdim);
|
||||
oc_inq_dim(nccomm->oc.conn,ocdim,&declsize,&ocname);
|
||||
oc_dds_ithdimension(nccomm->oc.conn,ocnode,i,&ocdim);
|
||||
oc_dimension_properties(nccomm->oc.conn,ocdim,&declsize,&ocname);
|
||||
|
||||
cdfdim = makecdfnode34(nccomm,ocname,OC_Dimension,
|
||||
ocdim,cdfnode->container);
|
||||
@ -520,7 +520,7 @@ applyclientparams34(NCDAPCOMMON* nccomm)
|
||||
const char* value;
|
||||
char tmpname[NC_MAX_NAME+32];
|
||||
char* pathstr;
|
||||
OCconnection conn = nccomm->oc.conn;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
unsigned long limit;
|
||||
|
||||
ASSERT(nccomm->oc.url != NULL);
|
||||
@ -633,7 +633,7 @@ freecdfroot34(CDFnode* root)
|
||||
/* Explicitly FREE the ocroot */
|
||||
nccomm = tree->owner;
|
||||
oc_root_free(nccomm->oc.conn,tree->ocroot);
|
||||
tree->ocroot = OCNULL;
|
||||
tree->ocroot = NULL;
|
||||
for(i=0;i<nclistlength(tree->nodes);i++) {
|
||||
CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
|
||||
free1cdfnode34(node);
|
||||
@ -700,7 +700,7 @@ simplenodematch34(CDFnode* node1, CDFnode* node2)
|
||||
}
|
||||
/* Add hack to address the screwed up Columbia server */
|
||||
if(node1->nctype == NC_Dataset) return 1;
|
||||
if(node1->nctype == NC_Primitive
|
||||
if(node1->nctype == NC_Atomic
|
||||
&& node1->etype != node2->etype) return 0;
|
||||
if(node1->ocname != NULL && node2->ocname != NULL
|
||||
&& strcmp(node1->ocname,node2->ocname)!=0) return 0;
|
||||
@ -798,7 +798,7 @@ fprintf(stderr,"attachnode: %s->%s\n",xnode->ocname,templatepathnode->ocname);
|
||||
if(simplenodematch34(xsubnode,templatepathnext)) {
|
||||
ncstat = attach34r(xsubnode,templatepath,depth+1);
|
||||
if(ncstat) goto done;
|
||||
} else if(gridable && xsubnode->nctype == NC_Primitive) {
|
||||
} else if(gridable && xsubnode->nctype == NC_Atomic) {
|
||||
/* grids may or may not appear in the datadds;
|
||||
try to match the xnode subnodes against the parts of the grid
|
||||
*/
|
||||
|
@ -5,7 +5,6 @@
|
||||
*********************************************************************/
|
||||
|
||||
#include "ncdap3.h"
|
||||
#include "dapodom.h"
|
||||
#include "dapdebug.h"
|
||||
#include "dapdump.h"
|
||||
#include "dceparselex.h"
|
||||
@ -117,7 +116,7 @@ qualifyprojectionnames3(DCEprojection* proj)
|
||||
|
||||
ASSERT((proj->discrim == CES_VAR
|
||||
&& proj->var->annotation != NULL
|
||||
&& ((CDFnode*)proj->var->annotation)->ocnode != OCNULL));
|
||||
&& ((CDFnode*)proj->var->annotation)->ocnode != NULL));
|
||||
collectnodepath3((CDFnode*)proj->var->annotation,fullpath,!WITHDATASET);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"qualify: %s -> ",
|
||||
@ -256,7 +255,7 @@ matchpartialname3(NClist* nodes, NClist* segments, CDFnode** nodep)
|
||||
if(node->nctype != NC_Sequence
|
||||
&& node->nctype != NC_Structure
|
||||
&& node->nctype != NC_Grid
|
||||
&& node->nctype != NC_Primitive
|
||||
&& node->nctype != NC_Atomic
|
||||
)
|
||||
continue;
|
||||
nclistpush(namematches,(ncelem)node);
|
||||
@ -407,25 +406,31 @@ buildconstraintstring3(DCEconstraint* constraints)
|
||||
with any pseudo dimensions removed
|
||||
*/
|
||||
NCerror
|
||||
buildvaraprojection3(Getvara* getvar,
|
||||
buildvaraprojection3(CDFnode* var,
|
||||
const size_t* startp, const size_t* countp, const ptrdiff_t* stridep,
|
||||
DCEprojection** projectionp)
|
||||
{
|
||||
int i,j;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
CDFnode* var = getvar->target;
|
||||
DCEprojection* projection = NULL;
|
||||
NClist* path = nclistnew();
|
||||
NClist* segments = NULL;
|
||||
int dimindex;
|
||||
|
||||
/* Build a skeleton projection that has 1 segment for
|
||||
every cdfnode from root to the variable of interest.
|
||||
Each segment has the slices from its corresponding node
|
||||
in the path, including pseudo-dims
|
||||
*/
|
||||
ncstat = dapvar2projection(var,&projection);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"buildvaraprojection: %s\n",dumpprojection(projection));
|
||||
fprintf(stderr,"buildvaraprojection: skeleton: %s\n",dumpprojection(projection));
|
||||
#endif
|
||||
|
||||
/* We need to assign the start/count/stride info to each segment;
|
||||
declsize will have been set
|
||||
/* Now, modify the projection to reflect the corresponding
|
||||
start/count/stride from the nc_get_vara arguments.
|
||||
*/
|
||||
segments = projection->var->segments;
|
||||
dimindex = 0;
|
||||
@ -452,7 +457,7 @@ fprintf(stderr,"buildvaraprojection.final: %s\n",dumpprojection(projection));
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"buildvaraprojection3: projection=%s\n",
|
||||
fprintf(stderr,"buildvaraprojection3: final: projection=%s\n",
|
||||
dumpprojection(projection));
|
||||
#endif
|
||||
|
||||
@ -710,7 +715,7 @@ dapvar2projection(CDFnode* var, DCEprojection** projectionp)
|
||||
DCEprojection* projection = NULL;
|
||||
int dimindex;
|
||||
|
||||
/* Collect the nodes needed to construct the projection segment */
|
||||
/* Collect the nodes needed to construct the projection segments */
|
||||
collectnodepath3(var,path,!WITHDATASET);
|
||||
|
||||
segments = nclistnew();
|
||||
@ -851,3 +856,31 @@ fprintf(stderr,"dapshiftprojection.after: %s\n",dumpprojection(projection));
|
||||
|
||||
return ncstat;
|
||||
}
|
||||
|
||||
/* Compute the set of variables referenced in the projections
|
||||
of the input constraint.
|
||||
*/
|
||||
NCerror
|
||||
computeprojectedvars(NCDAPCOMMON* dapcomm, DCEconstraint* constraint)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
NClist* vars = nclistnew();
|
||||
int i;
|
||||
|
||||
dapcomm->cdf.projectedvars = vars;
|
||||
if(constraint == NULL || constraint->projections == NULL)
|
||||
goto done;
|
||||
|
||||
for(i=0;i<nclistlength(constraint->projections);i++) {
|
||||
CDFnode* node;
|
||||
DCEprojection* proj = (DCEprojection*)nclistget(constraint->projections,i);
|
||||
if(proj->discrim == CES_FCN) continue; /* ignore these */
|
||||
node = (CDFnode*)proj->var->annotation;
|
||||
if(!nclistcontains(vars,(ncelem)node)) {
|
||||
nclistpush(vars,(ncelem)node);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return ncstat;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
extern NCerror parsedapconstraints(NCDAPCOMMON*, char*, DCEconstraint*);
|
||||
extern NCerror mapconstraints3(DCEconstraint*,CDFnode*);
|
||||
extern NCerror qualifyconstraints3(DCEconstraint* constraint);
|
||||
extern NCerror computeprojectedvars(NCDAPCOMMON*,DCEconstraint*);
|
||||
|
||||
extern char* simplepathstring(NClist* segments, char* separator);
|
||||
extern void makesegmentstring3(NClist* segments, NCbytes* buf, char* separator);
|
||||
|
@ -4,7 +4,6 @@
|
||||
* $Header: /upc/share/CVS/netcdf-3/libncdap4/constraints4.c,v 1.9 2010/04/13 03:36:31 dmh Exp $
|
||||
*********************************************************************/
|
||||
#include "ncdap4.h"
|
||||
#include "dapodom.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "dapdump.h"
|
||||
|
@ -6,17 +6,114 @@
|
||||
|
||||
#include "ncdap3.h"
|
||||
|
||||
#define OCHECK(exp) if((ocstat = (exp))) goto done;
|
||||
#define OCCHECK(exp) if((ocstat = (exp))) {THROWCHK(ocstat); goto done;}
|
||||
|
||||
/* Forward */
|
||||
static NCerror buildattribute(char*,nc_type,NClist*,NCattribute**);
|
||||
static int mergedas1(NCDAPCOMMON*, OCconnection, CDFnode* dds, OCobject das);
|
||||
static int isglobalname3(char* name);
|
||||
static NCerror buildattribute(char*,nc_type,size_t,char**,NCattribute**);
|
||||
|
||||
/*
|
||||
Invoke oc_merge_das and then extract special
|
||||
attributes such as "strlen" and "dimname"
|
||||
and stuff from DODS_EXTRA.
|
||||
*/
|
||||
int
|
||||
dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
|
||||
{
|
||||
int i,j;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NClist* allnodes;
|
||||
OClink conn;
|
||||
|
||||
conn = nccomm->oc.conn;
|
||||
|
||||
if(ddsroot == NULL || dasroot == NULL) return NC_NOERR;
|
||||
/* Merge the das tree onto the dds tree */
|
||||
ocstat = oc_merge_das(nccomm->oc.conn,dasroot,ddsroot);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
|
||||
/* Create attributes on CDFnodes */
|
||||
allnodes = nccomm->cdf.ddsroot->tree->nodes;
|
||||
for(i=0;i<nclistlength(allnodes);i++) {
|
||||
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
|
||||
OCddsnode ocnode = node->ocnode;
|
||||
char* ocname;
|
||||
size_t attrcount;
|
||||
OCtype ocetype;
|
||||
|
||||
OCCHECK(oc_dds_attr_count(conn,ocnode,&attrcount));
|
||||
for(j=0;j<attrcount;j++) {
|
||||
size_t nvalues;
|
||||
char** values = NULL;
|
||||
NCattribute* att = NULL;
|
||||
|
||||
OCCHECK(oc_dds_attr(conn,ocnode,j,&ocname,&ocetype,&nvalues,NULL));
|
||||
if(nvalues > 0) {
|
||||
values = (char**)malloc(sizeof(char*)*nvalues);
|
||||
if(values == NULL) {ncstat = NC_ENOMEM; goto done;}
|
||||
OCCHECK(oc_dds_attr(conn,ocnode,j,NULL,NULL,NULL,values));
|
||||
}
|
||||
ncstat = buildattribute(ocname,octypetonc(ocetype),nvalues,values,&att);
|
||||
if(ncstat != NC_NOERR) goto done;
|
||||
if(node->attributes == NULL)
|
||||
node->attributes = nclistnew();
|
||||
nclistpush(node->attributes,(ncelem)att);
|
||||
if(strncmp(ocname,"DODS",strlen("DODS"))==0) {
|
||||
att->invisible = 1;
|
||||
/* Define extra semantics associated with
|
||||
DODS and DODS_EXTRA attributes */
|
||||
if(strcmp(ocname,"DODS.strlen")==0
|
||||
|| strcmp(ocname,"DODS_EXTRA.strlen")==0) {
|
||||
unsigned int maxstrlen = 0;
|
||||
if(values != NULL) {
|
||||
if(0==sscanf(values[0],"%u",&maxstrlen))
|
||||
maxstrlen = 0;
|
||||
}
|
||||
node->dodsspecial.maxstrlen = maxstrlen;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"%s.maxstrlen=%d\n",node->ocname,(int)node->dodsspecial.maxstrlen);
|
||||
#endif
|
||||
} else if(strcmp(ocname,"DODS.dimName")==0
|
||||
|| strcmp(ocname,"DODS_EXTRA.dimName")==0) {
|
||||
if(values != NULL) {
|
||||
node->dodsspecial.dimname = nulldup(values[0]);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"%s.dimname=%s\n",node->ocname,node->dodsspecial.dimname);
|
||||
#endif
|
||||
} else node->dodsspecial.dimname = NULL;
|
||||
} else if(strcmp(ocname,"DODS.Unlimited_Dimension")==0
|
||||
|| strcmp(ocname,"DODS_EXTRA.Unlimited_Dimension")==0) {
|
||||
if(values != NULL) {
|
||||
if(nccomm->cdf.recorddimname != NULL)
|
||||
nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
|
||||
else
|
||||
nccomm->cdf.recorddimname = nulldup(values[0]);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"%s.Unlimited_Dimension=%s\n",node->ocname,nccomm->cdf.recorddimname);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* clean up */
|
||||
if(values) {
|
||||
oc_reclaim_strings(nvalues,values);
|
||||
free(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
/* Build an NCattribute */
|
||||
static NCerror
|
||||
buildattribute(char* name, nc_type ptype,
|
||||
NClist* values, NCattribute** attp)
|
||||
size_t nvalues, char** values, NCattribute** attp)
|
||||
{
|
||||
int i;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
NCattribute* att;
|
||||
|
||||
@ -25,67 +122,61 @@ buildattribute(char* name, nc_type ptype,
|
||||
att->name = nulldup(name);
|
||||
att->etype = ptype;
|
||||
|
||||
att->values = values;
|
||||
att->values = nclistnew();
|
||||
for(i=0;i<nvalues;i++)
|
||||
nclistpush(att->values,(ncelem)nulldup(values[i]));
|
||||
|
||||
if(attp) *attp = att;
|
||||
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Given a das attribute walk it to see if it
|
||||
has at least 1 actual attribute (no recursion)
|
||||
*/
|
||||
static int
|
||||
hasattribute3(OCconnection conn, OCobject dasnode)
|
||||
hasattribute3(OClink conn, OCdasnode dasnode)
|
||||
{
|
||||
int i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
int tf = 0; /* assume false */
|
||||
unsigned int nsubnodes;
|
||||
OCtype ocsubtype;
|
||||
OCobject* subnodes = NULL;
|
||||
NClist* subnodes = nclistnew();
|
||||
|
||||
OCHECK(oc_inq_class(conn,dasnode,&ocsubtype));
|
||||
OCCHECK(oc_dds_octype(conn,dasnode,&ocsubtype));
|
||||
if(ocsubtype == OC_Attribute) return 1; /* this is an attribute */
|
||||
ASSERT((ocsubtype == OC_Attributeset));
|
||||
|
||||
OCHECK(oc_inq_nsubnodes(conn,dasnode,&nsubnodes));
|
||||
OCHECK(oc_inq_subnodes(conn,dasnode,&subnodes));
|
||||
for(i=0;i<nsubnodes;i++) {
|
||||
OCobject subnode = subnodes[i];
|
||||
OCHECK(oc_inq_class(conn,subnode,&ocsubtype));
|
||||
OCCHECK(collect_subnodes(conn,dasnode,subnodes));
|
||||
for(i=0;i<nclistlength(subnodes);i++) {
|
||||
OCdasnode subnode = (OCdasnode)nclistget(subnodes,i);
|
||||
OCCHECK(oc_dds_class(conn,subnode,&ocsubtype));
|
||||
if(ocsubtype == OC_Attribute) {tf=1; break;}
|
||||
}
|
||||
done:
|
||||
nullfree(subnodes);
|
||||
nclistfree(subnodes);
|
||||
return tf;
|
||||
}
|
||||
|
||||
/*
|
||||
Duplicate the oc merge das and dds code, but
|
||||
modify to capture such things as "strlen" and "dimname".
|
||||
*/
|
||||
|
||||
int
|
||||
dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCobject dasroot)
|
||||
dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
|
||||
{
|
||||
unsigned int i,j;
|
||||
NCerror ncerr = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCconnection conn = nccomm->oc.conn;
|
||||
unsigned int nsubnodes, nobjects;
|
||||
OCobject* dasobjects = NULL;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
size_t nsubnodes;
|
||||
NClist* dasglobals = nclistnew();
|
||||
NClist* dasnodes = nclistnew();
|
||||
NClist* dodsextra = nclistnew();
|
||||
NClist* varnodes = nclistnew();
|
||||
NClist* allddsnodes = ddsroot->tree->nodes;
|
||||
NClist* alldasnodes = nclistnew();
|
||||
|
||||
if(ddsroot == NULL || dasroot == NULL) return NC_NOERR;
|
||||
|
||||
nobjects = oc_inq_nobjects(conn,dasroot);
|
||||
dasobjects = oc_inq_objects(conn,dasroot);
|
||||
ocstat = collect_alldasnodes(conn,dasroot,alldasnodes);
|
||||
|
||||
/* 1. collect all the relevant DAS nodes;
|
||||
namely those that contain at least one
|
||||
@ -94,18 +185,18 @@ dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCobject dasroot)
|
||||
if found; complain but continue: result are indeterminate.
|
||||
also collect globals and DODS_EXTRA separately.
|
||||
*/
|
||||
for(i=0;i<nobjects;i++) {
|
||||
OCobject das = dasobjects[i];
|
||||
for(i=0;i<nclistlength(alldasnodes);i++) {
|
||||
OCddsnode das = (OCddsnode)nclistget(alldasnodes,i);
|
||||
OCtype octype;
|
||||
char* ocname = NULL;
|
||||
int isglobal = 0;
|
||||
int hasattributes = 0;
|
||||
|
||||
OCHECK(oc_inq_class(conn,das,&octype));
|
||||
OCCHECK(oc_dds_class(conn,das,&octype));
|
||||
if(octype == OC_Attribute) continue; /* ignore these for now*/
|
||||
|
||||
OCHECK(oc_inq_name(conn,das,&ocname));
|
||||
OCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
|
||||
OCCHECK(oc_dds_name(conn,das,&ocname));
|
||||
OCCHECK(oc_dds_nsubnodes(conn,das,&nsubnodes));
|
||||
|
||||
isglobal = (ocname == NULL ? 0 : isglobalname3(ocname));
|
||||
|
||||
@ -124,9 +215,9 @@ dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCobject dasroot)
|
||||
if(hasattributes) {
|
||||
/* Look for previously collected nodes with same name*/
|
||||
for(j=0;j<nclistlength(dasnodes);j++) {
|
||||
OCobject das2 = (OCobject)nclistget(dasnodes,j);
|
||||
OCddsnode das2 = (OCddsnode)nclistget(dasnodes,j);
|
||||
char* ocname2;
|
||||
OCHECK(oc_inq_name(conn,das2,&ocname2));
|
||||
OCCHECK(oc_dds_name(conn,das2,&ocname2));
|
||||
if(ocname2 == NULL || ocname == NULL) goto loop;
|
||||
if(strcmp(ocname2,"DODS")==0) goto loop;
|
||||
if(strcmp(ocname,ocname2)==0)
|
||||
@ -139,13 +230,10 @@ loop:
|
||||
nullfree(ocname);
|
||||
}
|
||||
|
||||
/* 2. collect all the leaf DDS nodes (of type NC_Primitive)*/
|
||||
for(i=0;i<nclistlength(allddsnodes);i++) {
|
||||
CDFnode* dds = (CDFnode*)nclistget(allddsnodes,i);
|
||||
if(dds->nctype == NC_Primitive) nclistpush(varnodes,(ncelem)dds);
|
||||
}
|
||||
/* 2. collect all the leaf DDS nodes (of type NC_Atomic)*/
|
||||
ocstat = collect_leaves(link,ddsroot,varnodes);
|
||||
|
||||
/* 3. For each das node, lncate matching DDS node(s) and attach
|
||||
/* 3. For each das node, locate matching DDS node(s) and attach
|
||||
attributes to the DDS node(s).
|
||||
Match means:
|
||||
1. DAS->fullname :: DDS->fullname
|
||||
@ -154,18 +242,16 @@ loop:
|
||||
4. special case for DODS. Apply 1-3 on DODS parent.
|
||||
*/
|
||||
for(i=0;i<nclistlength(dasnodes);i++) {
|
||||
OCobject das = (OCobject)nclistget(dasnodes,i);
|
||||
OCddsnode das = (OCddsnode)nclistget(dasnodes,i);
|
||||
char* ocfullname = NULL;
|
||||
char* ocbasename = NULL;
|
||||
|
||||
if(das == OCNULL) continue;
|
||||
OCHECK(oc_inq_name(conn,das,&ocbasename));
|
||||
if(das == NULL) continue;
|
||||
OCCHECK(oc_dds_name(conn,das,&ocbasename));
|
||||
if(strcmp(ocbasename,"DODS")==0) {
|
||||
OCobject container;
|
||||
OCHECK(oc_inq_container(conn,das,&container));
|
||||
if(container == OCNULL) {
|
||||
ASSERT(container != OCNULL);
|
||||
}
|
||||
OCddsnode container;
|
||||
OCCHECK(oc_dds_container(conn,das,&container));
|
||||
ASSERT(container != NULL);
|
||||
ocfullname = makeocpathstring3(conn,container,".");
|
||||
} else {
|
||||
ocfullname = makeocpathstring3(conn,das,".");
|
||||
@ -188,28 +274,29 @@ loop:
|
||||
|
||||
/* 4. Assign globals */
|
||||
for(i=0;i<nclistlength(dasglobals);i++) {
|
||||
OCobject das = (OCobject)nclistget(dasglobals,i);
|
||||
OCddsnode das = (OCddsnode)nclistget(dasglobals,i);
|
||||
mergedas1(nccomm,conn,ddsroot,das);
|
||||
}
|
||||
|
||||
/* 5. Assign DOD_EXTRA */
|
||||
for(i=0;i<nclistlength(dodsextra);i++) {
|
||||
OCobject das = (OCobject)nclistget(dodsextra,i);
|
||||
OCddsnode das = (OCddsnode)nclistget(dodsextra,i);
|
||||
mergedas1(nccomm,conn,ddsroot,das);
|
||||
}
|
||||
|
||||
done: /* cleanup*/
|
||||
nullfree(dasobjects);
|
||||
nclistfree(dasglobals);
|
||||
nclistfree(dasnodes);
|
||||
nclistfree(alldasnodes);
|
||||
nclistfree(dodsextra);
|
||||
nclistfree(varnodes);
|
||||
if(ocstat != OC_NOERR) ncerr = ocerrtoncerr(ocstat);
|
||||
if(ocstat != OC_NOERR)
|
||||
ncerr = ocerrtoncerr(ocstat);
|
||||
return THROW(ncerr);
|
||||
}
|
||||
|
||||
static int
|
||||
mergedas1(NCDAPCOMMON* nccomm, OCconnection conn, CDFnode* dds, OCobject das)
|
||||
mergedas1(NCDAPCOMMON* nccomm, OClink conn, CDFnode* dds, OCddsnode das)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
@ -222,24 +309,24 @@ mergedas1(NCDAPCOMMON* nccomm, OCconnection conn, CDFnode* dds, OCobject das)
|
||||
if(dds == NULL || das == OCNULL) return NC_NOERR; /* nothing to do */
|
||||
if(dds->attributes == NULL) dds->attributes = nclistnew();
|
||||
/* assign the simple attributes in the das set to this dds node*/
|
||||
OCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
|
||||
OCHECK(oc_inq_subnodes(conn,das,&subnodes));
|
||||
OCCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
|
||||
OCCHECK(oc_inq_subnodes(conn,das,&subnodes));
|
||||
for(i=0;i<nsubnodes;i++) {
|
||||
OCobject attnode = subnodes[i];
|
||||
OCtype octype, ocetype;
|
||||
char* ocname = NULL;
|
||||
unsigned int ocnvalues;
|
||||
OCHECK(oc_inq_name(conn,attnode,&ocname));
|
||||
OCHECK(oc_inq_class(conn,attnode,&octype));
|
||||
OCCHECK(oc_inq_name(conn,attnode,&ocname));
|
||||
OCCHECK(oc_inq_class(conn,attnode,&octype));
|
||||
if(octype == OC_Attribute) {
|
||||
NCattribute* att = NULL;
|
||||
NClist* stringvalues;
|
||||
OCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
||||
OCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
||||
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
||||
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
||||
stringvalues = nclistnew();
|
||||
for(j=0;j<ocnvalues;j++) {
|
||||
char* stringval;
|
||||
OCHECK(oc_inq_dasattr(conn,attnode,j,&ocetype,&stringval));
|
||||
OCCHECK(oc_inq_dasattr(conn,attnode,j,&ocetype,&stringval));
|
||||
nclistpush(stringvalues,(ncelem)stringval);
|
||||
}
|
||||
ncstat = buildattribute(ocname,
|
||||
@ -253,25 +340,25 @@ mergedas1(NCDAPCOMMON* nccomm, OCconnection conn, CDFnode* dds, OCobject das)
|
||||
|| strcmp(ocname,"DODS_EXTRA")==0)) {
|
||||
/* Turn the DODS special attributes into into
|
||||
special attributes for dds node */
|
||||
OCHECK(oc_inq_nsubnodes(conn,attnode,&ndodsnodes));
|
||||
OCHECK(oc_inq_subnodes(conn,attnode,&dodsnodes));
|
||||
OCCHECK(oc_inq_nsubnodes(conn,attnode,&ndodsnodes));
|
||||
OCCHECK(oc_inq_subnodes(conn,attnode,&dodsnodes));
|
||||
for(j=0;j<ndodsnodes;j++) {
|
||||
char* dodsname = NULL;
|
||||
char newname[4096];
|
||||
OCobject attnode = dodsnodes[j];
|
||||
NCattribute* att = NULL;
|
||||
NClist* stringvalues;
|
||||
OCHECK(oc_inq_class(conn,attnode,&octype));
|
||||
OCCHECK(oc_inq_class(conn,attnode,&octype));
|
||||
if(octype != OC_Attribute) continue;
|
||||
OCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
||||
OCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
||||
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
||||
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
||||
stringvalues = nclistnew();
|
||||
for(k=0;k<ocnvalues;k++) {
|
||||
char* stringval;
|
||||
OCHECK(oc_inq_dasattr(conn,attnode,k,&ocetype,&stringval));
|
||||
OCCHECK(oc_inq_dasattr(conn,attnode,k,&ocetype,&stringval));
|
||||
nclistpush(stringvalues,(ncelem)stringval);
|
||||
}
|
||||
OCHECK(oc_inq_name(conn,attnode,&dodsname));
|
||||
OCCHECK(oc_inq_name(conn,attnode,&dodsname));
|
||||
/* Compute new special name */
|
||||
strcpy(newname,"_DODS_");
|
||||
strcat(newname,dodsname);
|
||||
@ -339,3 +426,68 @@ isglobalname3(char* name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static OCerror
|
||||
collect_alldasnodes(OClink link, OCddsnode dasnode, NClist* alldasnodes)
|
||||
{
|
||||
size_t nsubnodes,i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
nclistpush(alldasnodes,(ncelem)dasnode);
|
||||
ocstat = oc_dds_nsubnodes(link,dasnode,&nsubnodes);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
for(i=0;i<nsubnodes;i++) {
|
||||
OCddsnode subnode;
|
||||
ocstat = oc_dds_ithsubnode(link,dasnode,i,&subnode);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
ocstat = collect_alldasnodes(link,subnode,alldasnodes);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return ocstat;
|
||||
}
|
||||
|
||||
static OCerror
|
||||
collect_leaves(OClink link, OCddsnode ddsnode, NClist* leaves)
|
||||
{
|
||||
size_t nsubnodes,i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCtype octype;
|
||||
ocstat = oc_dds_octype(link,ddsnode,&octype);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
if(octype == OC_Atomic) {
|
||||
nclistpush(leaves,(ncelem)ddsnode);
|
||||
} else {
|
||||
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
for(i=0;i<nsubnodes;i++) {
|
||||
OCddsnode subnode;
|
||||
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
ocstat = collect_leaves(link,subnode,leaves);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return ocstat;
|
||||
}
|
||||
|
||||
static OCerror
|
||||
collect_subnodes(OClink link, OCddsnode ddsnode, NClist* subnodes)
|
||||
{
|
||||
size_t nsubnodes,i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
for(i=0;i<nsubnodes;i++) {
|
||||
OCddsnode subnode;
|
||||
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
nclistpush(subnodes,(ncelem)subnode);
|
||||
}
|
||||
|
||||
done:
|
||||
return ocstat;
|
||||
}
|
||||
#endif /*0*/
|
||||
|
@ -5,7 +5,6 @@
|
||||
*********************************************************************/
|
||||
#include "config.h"
|
||||
#include "ncdap3.h"
|
||||
#include "dapodom.h"
|
||||
|
||||
NCerror
|
||||
dapconvert3(nc_type srctype, nc_type dsttype, char* memory0, char* value0, size_t count)
|
||||
|
@ -27,8 +27,8 @@
|
||||
#include <assert.h>
|
||||
|
||||
/* Warning: setting CATCHERROR has significant performance impact */
|
||||
#undef CATCHERROR
|
||||
#ifdef DEBUG
|
||||
#define CATCHERROR
|
||||
#ifdef DAPDEBUG
|
||||
#undef CATCHERROR
|
||||
#define CATCHERROR
|
||||
#endif
|
||||
@ -59,15 +59,13 @@ extern int dapthrow(int err);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define SHOWFETCH (1)
|
||||
#define LOG0(level,msg) fprintf(stderr,msg)
|
||||
#define LOG1(level,msg,a1) fprintf(stderr,msg,a1)
|
||||
#define LOG2(level,msg,a1,a2) fprintf(stderr,msg,a1,a2)
|
||||
#else
|
||||
#define SHOWFETCH FLAGSET(nccomm->controls,NCF_SHOWFETCH)
|
||||
#endif
|
||||
|
||||
#define LOG0(level,msg) nclog(level,msg)
|
||||
#define LOG1(level,msg,a1) nclog(level,msg,a1)
|
||||
#define LOG2(level,msg,a1,a2) nclog(level,msg,a1,a2)
|
||||
#endif
|
||||
|
||||
#endif /*DEBUG_H*/
|
||||
|
||||
|
@ -325,7 +325,7 @@ dumptreer(CDFnode* root, NCbytes* buf, int indent, int visible)
|
||||
case NC_Grid:
|
||||
dumptreer1(root,buf,indent,"Grid",visible);
|
||||
break;
|
||||
case NC_Primitive:
|
||||
case NC_Atomic:
|
||||
switch (root->etype) {
|
||||
case NC_BYTE: primtype = "byte"; break;
|
||||
case NC_CHAR: primtype = "char"; break;
|
||||
@ -406,7 +406,7 @@ dumpnode(CDFnode* node)
|
||||
case NC_Sequence: nctype = "Sequence"; break;
|
||||
case NC_Structure: nctype = "Structure"; break;
|
||||
case NC_Grid: nctype = "Grid"; break;
|
||||
case NC_Primitive:
|
||||
case NC_Atomic:
|
||||
switch (node->etype) {
|
||||
case NC_BYTE: primtype = "byte"; break;
|
||||
case NC_CHAR: primtype = "char"; break;
|
||||
@ -605,3 +605,28 @@ dumpslices(DCEslice* slice, unsigned int rank)
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
dumpraw(void* o)
|
||||
{
|
||||
fprintf(stderr,"%s\n",dcerawtostring(o));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void
|
||||
dumplistraw(NClist* l)
|
||||
{
|
||||
fprintf(stderr,"%s\n",dcerawlisttostring(l));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/* For debugging */
|
||||
void
|
||||
dumpstringlist(NClist* l)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<nclistlength(l);i++) {
|
||||
const char* s = (const char*)nclistget(l,i);
|
||||
fprintf(stderr,"[%d]: |%s|\n",i,s);
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
|
@ -63,6 +63,8 @@ extern char* dumpsegments(NClist* segments);
|
||||
extern char* dumpslice(DCEslice* slice);
|
||||
extern char* dumpslices(DCEslice* slice, unsigned int rank);
|
||||
|
||||
extern void dumpraw(void*);
|
||||
extern void dumplistraw(NClist*);
|
||||
|
||||
#endif /*DUMP_H*/
|
||||
|
||||
|
@ -10,75 +10,61 @@
|
||||
/**********************************************/
|
||||
/* Define methods for a dimension dapodometer*/
|
||||
|
||||
/* Build an odometer covering slices startslice upto, but not including, stopslice */
|
||||
Dapodometer*
|
||||
newdapodometer(DCEslice* slices, unsigned int first, unsigned int rank)
|
||||
dapodom_fromsegment(DCEsegment* segment, size_t startslice, size_t stopslice)
|
||||
{
|
||||
int i;
|
||||
Dapodometer* odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
Dapodometer* odom;
|
||||
|
||||
assert(stopslice > startslice);
|
||||
assert((stopslice - startslice) <= NC_MAX_VAR_DIMS);
|
||||
odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
MEMCHECK(odom,NULL);
|
||||
if(rank == 0) {
|
||||
return newdapodometer1(1);
|
||||
}
|
||||
odom->rank = rank;
|
||||
ASSERT(odom->rank <= NC_MAX_VAR_DIMS);
|
||||
odom->rank = (stopslice - startslice);
|
||||
for(i=0;i<odom->rank;i++) {
|
||||
DCEslice* slice = slices+(first+i);
|
||||
odom->slices[i] = *slice;
|
||||
odom->index[i] = odom->slices[i].first;
|
||||
odom->start[i] = segment->slices[i+startslice].first;
|
||||
odom->count[i] = segment->slices[i+startslice].count;
|
||||
odom->stride[i] = segment->slices[i+startslice].stride;
|
||||
odom->declsize[i] = segment->slices[i+startslice].declsize;
|
||||
odom->stop[i] = odom->start[i] + odom->count[i];
|
||||
odom->index[i] = odom->start[i];
|
||||
}
|
||||
return odom;
|
||||
}
|
||||
|
||||
Dapodometer*
|
||||
newsimpledapodometer(DCEsegment* segment, unsigned int rank)
|
||||
dapodom_new(size_t rank,
|
||||
const size_t* start, const size_t* count,
|
||||
const ptrdiff_t* stride, const size_t* size)
|
||||
{
|
||||
int i;
|
||||
Dapodometer* odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
MEMCHECK(odom,NULL);
|
||||
if(rank == 0) {
|
||||
return newdapodometer1(1);
|
||||
}
|
||||
odom->rank = rank;
|
||||
assert(odom->rank <= NC_MAX_VAR_DIMS);
|
||||
assert(segment->slicesdefined && segment->slicesdeclized);
|
||||
for(i=0;i<odom->rank;i++) {
|
||||
DCEslice* odslice = &odom->slices[i];
|
||||
DCEslice* segslice = &segment->slices[i];
|
||||
odslice->first = 0;
|
||||
odslice->stride = 1;
|
||||
odslice->declsize = segslice->count;
|
||||
odslice->length = odslice->declsize;
|
||||
odslice->stop = odslice->declsize;
|
||||
odslice->count = odslice->declsize;
|
||||
odom->index[i] = 0;
|
||||
odom->start[i] = (start != NULL ? start[i] : 0);
|
||||
odom->count[i] = (count != NULL ? count[i]
|
||||
: (size != NULL ? size[i] : 1));
|
||||
odom->stride[i] = (size_t)(stride != NULL ? stride[i] : 1);
|
||||
odom->declsize[i] = (size != NULL ? size[i]
|
||||
: (odom->start[i]+odom->count[i]));
|
||||
odom->stop[i] = odom->start[i] + odom->count[i];
|
||||
odom->index[i] = odom->start[i];
|
||||
}
|
||||
return odom;
|
||||
}
|
||||
|
||||
Dapodometer*
|
||||
newdapodometer1(unsigned int count)
|
||||
{
|
||||
Dapodometer* odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
MEMCHECK(odom,NULL);
|
||||
odom->rank = 1;
|
||||
odom->slices[0].first = 0;
|
||||
odom->slices[0].length = count;
|
||||
odom->slices[0].stride = 1;
|
||||
odom->slices[0].stop = count;
|
||||
odom->slices[0].declsize = count;
|
||||
odom->slices[0].count = count;
|
||||
odom->index[0] = 0;
|
||||
return odom;
|
||||
}
|
||||
|
||||
void
|
||||
freedapodometer(Dapodometer* odom)
|
||||
dapodom_free(Dapodometer* odom)
|
||||
{
|
||||
if(odom) free(odom);
|
||||
}
|
||||
|
||||
#if 0
|
||||
char*
|
||||
dapodometerprint(Dapodometer* odom)
|
||||
dapodom_print(Dapodometer* odom)
|
||||
{
|
||||
int i;
|
||||
static char line[1024];
|
||||
@ -88,165 +74,80 @@ dapodometerprint(Dapodometer* odom)
|
||||
strcat(line,"[]");
|
||||
} else for(i=0;i<odom->rank;i++) {
|
||||
sprintf(tmp,"[%lu/%lu:%lu:%lu]",
|
||||
(unsigned long)odom->index[i],
|
||||
(unsigned long)odom->slices[i].first,
|
||||
(unsigned long)odom->slices[i].stride,
|
||||
(unsigned long)odom->slices[i].length);
|
||||
(size_t)odom->index[i],
|
||||
(size_t)odom->start[i],
|
||||
(size_t)odom->stride[i],
|
||||
(size_t)odom->length[i]);
|
||||
strcat(line,tmp);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
dapodometermore(Dapodometer* odom)
|
||||
dapodom_more(Dapodometer* odom)
|
||||
{
|
||||
return (odom->index[0] < odom->slices[0].stop);
|
||||
}
|
||||
|
||||
void
|
||||
dapodometerreset(Dapodometer* odom)
|
||||
{
|
||||
int rank = odom->rank;
|
||||
while(rank-- > 0) {odom->index[rank] = odom->slices[rank].first;}
|
||||
return (odom->index[0] < odom->stop[0]);
|
||||
}
|
||||
|
||||
/* Convert current dapodometer settings to a single integer count*/
|
||||
size_t
|
||||
dapodometercount(Dapodometer* odom)
|
||||
off_t
|
||||
dapodom_count(Dapodometer* odom)
|
||||
{
|
||||
int i;
|
||||
size_t offset = 0;
|
||||
off_t offset = 0;
|
||||
for(i=0;i<odom->rank;i++) {
|
||||
offset *= odom->slices[i].declsize;
|
||||
offset *= odom->declsize[i];
|
||||
offset += odom->index[i];
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a dapodometer, compute the total
|
||||
number of elements in its space
|
||||
as determined by declsize; start at
|
||||
offset wheel
|
||||
*/
|
||||
|
||||
size_t
|
||||
dapodometerspace(Dapodometer* odom, unsigned int wheel)
|
||||
{
|
||||
unsigned int i,rank = odom->rank;
|
||||
size_t count = 1;
|
||||
DCEslice* slice;
|
||||
ASSERT((wheel < rank));
|
||||
slice = odom->slices+wheel;
|
||||
for(i=wheel;i<rank;i++,slice++) {
|
||||
count *= slice->declsize;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
Compute the number of elements
|
||||
that will be returned as the odometer
|
||||
is incremented to its stop point.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dapodometerpoints(Dapodometer* odom)
|
||||
{
|
||||
unsigned int i,rank = odom->rank;
|
||||
size_t count = 1;
|
||||
DCEslice* slice = odom->slices;
|
||||
for(i=0;i<rank;i++,slice++) {
|
||||
size_t slicecount = (slice->length/slice->stride);
|
||||
count *= slicecount;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
dapodometerincr(Dapodometer* odom)
|
||||
{
|
||||
return dapodometerincrith(odom,-1);
|
||||
}
|
||||
|
||||
int
|
||||
dapodometerincrith(Dapodometer* odom, int wheel)
|
||||
dapodom_next(Dapodometer* odom)
|
||||
{
|
||||
int i; /* do not make unsigned */
|
||||
DCEslice* slice;
|
||||
if(odom->rank == 0) return 0;
|
||||
if(wheel < 0) wheel = (odom->rank - 1);
|
||||
for(slice=odom->slices+(wheel),i=wheel;i>=0;i--,slice--) {
|
||||
odom->index[i] += slice->stride;
|
||||
if(odom->index[i] < slice->stop) break;
|
||||
for(i=odom->rank-1;i>=0;i--) {
|
||||
odom->index[i] += odom->stride[i];
|
||||
if(odom->index[i] < odom->stop[i]) break;
|
||||
if(i == 0) return 0; /* leave the 0th entry if it overflows*/
|
||||
odom->index[i] = slice->first; /* reset this position*/
|
||||
odom->index[i] = odom->start[i]; /* reset this position*/
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
int
|
||||
dapodometervarmcount(Dapodometer* odom, const ptrdiff_t* steps, const size_t* declsizes)
|
||||
size_t
|
||||
dapodom_varmcount(Dapodometer* odom, const ptrdiff_t* steps, const size_t* declsizes)
|
||||
{
|
||||
int i;
|
||||
size_t offset = 0;
|
||||
for(i=0;i<odom->rank;i++) {
|
||||
size_t tmp;
|
||||
tmp = odom->index[i];
|
||||
tmp = tmp - odom->slices[i].first;
|
||||
tmp = tmp / odom->slices[i].stride;
|
||||
tmp = tmp - odom->start[i];
|
||||
tmp = tmp / odom->stride[i];
|
||||
tmp = tmp * steps[i];
|
||||
offset += tmp;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a dapodometer, compute the total
|
||||
number of elements in its space.
|
||||
*/
|
||||
|
||||
/* Return the current set of indices */
|
||||
size_t*
|
||||
dapodometerindices(Dapodometer* odom)
|
||||
#if 0
|
||||
off_t
|
||||
dapodom_space(Dapodometer* odom)
|
||||
{
|
||||
if(odom == NULL) return NULL;
|
||||
return odom->index;
|
||||
}
|
||||
|
||||
Dapodometer*
|
||||
newdapodometer2(const size_t* start, const size_t* count, const ptrdiff_t* stride,
|
||||
unsigned int first, unsigned int rank)
|
||||
{
|
||||
int i;
|
||||
Dapodometer* odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
MEMCHECK(odom,NULL);
|
||||
odom->rank = rank;
|
||||
assert(odom->rank <= NC_MAX_VAR_DIMS);
|
||||
size_t i;
|
||||
off_t count = 1;
|
||||
for(i=0;i<odom->rank;i++) {
|
||||
odom->slices[i].first = start[first+i];
|
||||
odom->slices[i].stride = (size_t)stride[first+i];
|
||||
odom->slices[i].length = count[first+i] * stride[first+i];
|
||||
odom->slices[i].stop = (odom->slices[i].first+odom->slices[i].length);
|
||||
odom->slices[i].declsize = odom->slices[i].stop;
|
||||
odom->slices[i].count = (odom->slices[i].length /odom->slices[i].stride);
|
||||
odom->index[i] = odom->slices[i].first;
|
||||
}
|
||||
return odom;
|
||||
}
|
||||
|
||||
Dapodometer*
|
||||
newdapodometer3(int rank, size_t* dimsizes)
|
||||
{
|
||||
int i;
|
||||
Dapodometer* odom = (Dapodometer*)calloc(1,sizeof(Dapodometer));
|
||||
MEMCHECK(odom,NULL);
|
||||
odom->rank = rank;
|
||||
for(i=0;i<rank;i++) {
|
||||
odom->slices[i].first = 0;
|
||||
odom->slices[i].length = dimsizes[i];
|
||||
odom->slices[i].stride = 1;
|
||||
odom->slices[i].stop = dimsizes[i];
|
||||
odom->slices[i].declsize = dimsizes[i];
|
||||
odom->slices[i].count = (odom->slices[i].length / odom->slices[i].stride);
|
||||
odom->index[i] = 0;
|
||||
count *= odom->size[i];
|
||||
}
|
||||
return odom;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
@ -9,34 +9,27 @@
|
||||
|
||||
typedef struct Dapodometer {
|
||||
int rank;
|
||||
DCEslice slices[NC_MAX_VAR_DIMS];
|
||||
size_t index[NC_MAX_VAR_DIMS];
|
||||
size_t start[NC_MAX_VAR_DIMS];
|
||||
size_t count[NC_MAX_VAR_DIMS];
|
||||
size_t stride[NC_MAX_VAR_DIMS];
|
||||
size_t stop[NC_MAX_VAR_DIMS];
|
||||
size_t declsize[NC_MAX_VAR_DIMS];
|
||||
} Dapodometer;
|
||||
|
||||
/* Odometer operators*/
|
||||
extern Dapodometer* newdapodometer(DCEslice* slices, unsigned int first, unsigned int count);
|
||||
extern Dapodometer* dapodom_fromsegment(DCEsegment* segment, size_t start, size_t stop);
|
||||
|
||||
extern Dapodometer* newsimpledapodometer(struct DCEsegment*,unsigned int);
|
||||
extern Dapodometer* dapodom_new(size_t rank,
|
||||
const size_t* start, const size_t* count,
|
||||
const ptrdiff_t* stride, const size_t* size);
|
||||
|
||||
extern Dapodometer* newdapodometer1(unsigned int count);
|
||||
extern Dapodometer* newdapodometer2(const size_t*, const size_t*,
|
||||
const ptrdiff_t*, unsigned int, unsigned int);
|
||||
extern Dapodometer* newdapodometer3(int, size_t*);
|
||||
extern void dapodom_free(Dapodometer*);
|
||||
|
||||
extern void freedapodometer(Dapodometer*);
|
||||
extern char* dapodometerprint(Dapodometer* odom);
|
||||
extern int dapodom_more(Dapodometer* odom);
|
||||
extern int dapodom_next(Dapodometer* odo);
|
||||
|
||||
extern int dapodometermore(Dapodometer* odom);
|
||||
extern int dapodometerincr(Dapodometer* odo);
|
||||
extern int dapodometerincrith(Dapodometer* odo,int);
|
||||
extern size_t dapodometercount(Dapodometer* odo);
|
||||
extern void dapodometerreset(Dapodometer*);
|
||||
extern Dapodometer* dapodometersplit(Dapodometer* odom, int tail);
|
||||
extern off_t dapodom_count(Dapodometer* odo);
|
||||
|
||||
extern size_t dapodometerspace(Dapodometer* odom, unsigned int wheel);
|
||||
extern size_t dapodometerpoints(Dapodometer*);
|
||||
|
||||
extern size_t* dapodometerindices(Dapodometer*);
|
||||
extern int dapodometervarmcount(Dapodometer*, const ptrdiff_t*, const size_t*);
|
||||
extern size_t dapodom_varmcount(Dapodometer*, const ptrdiff_t*, const size_t*);
|
||||
|
||||
#endif /*DAPODOM_H*/
|
||||
|
@ -9,11 +9,10 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "oc.h"
|
||||
extern int oc_dumpnode(OClink, OCobject);
|
||||
extern int oc_dumpnode(OClink, OCddsnode);
|
||||
|
||||
#include "ncdap3.h"
|
||||
#include "dapalign.h"
|
||||
#include "dapodom.h"
|
||||
|
||||
#define LBRACKET '['
|
||||
#define RBRACKET ']'
|
||||
@ -137,7 +136,7 @@ octypetonc(OCtype etype)
|
||||
case OC_Structure: return NC_Structure;
|
||||
case OC_Grid: return NC_Grid;
|
||||
case OC_Dimension: return NC_Dimension;
|
||||
case OC_Primitive: return NC_Primitive;
|
||||
case OC_Atomic: return NC_Atomic;
|
||||
default: break;
|
||||
}
|
||||
return NC_NAT;
|
||||
@ -213,7 +212,7 @@ nctypetostring(nc_type nctype)
|
||||
case NC_Structure: return "NC_Structure";
|
||||
case NC_Grid: return "NC_Grid";
|
||||
case NC_Dimension: return "NC_Dimension";
|
||||
case NC_Primitive: return "NC_Primitive";
|
||||
case NC_Atomic: return "NC_Atomic";
|
||||
default: break;
|
||||
}
|
||||
return NULL;
|
||||
@ -341,21 +340,21 @@ collectnodepath3(CDFnode* node, NClist* path, int withdataset)
|
||||
|
||||
/* Like collectnodepath3, but in ocspace */
|
||||
void
|
||||
collectocpath(OCconnection conn, OCobject node, NClist* path)
|
||||
collectocpath(OClink conn, OCddsnode node, NClist* path)
|
||||
{
|
||||
OCobject container;
|
||||
OCddsnode container;
|
||||
OCtype octype;
|
||||
if(node == OCNULL) return;
|
||||
oc_inq_class(conn,node,&octype);
|
||||
if(node == NULL) return;
|
||||
oc_dds_class(conn,node,&octype);
|
||||
if(octype == OC_Dataset) return;
|
||||
oc_inq_container(conn,node,&container);
|
||||
if(container != OCNULL)
|
||||
oc_dds_container(conn,node,&container);
|
||||
if(container != NULL)
|
||||
collectocpath(conn,container,path);
|
||||
nclistpush(path,(ncelem)node);
|
||||
}
|
||||
|
||||
char*
|
||||
makeocpathstring3(OCconnection conn, OCobject node, const char* sep)
|
||||
makeocpathstring3(OClink conn, OCddsnode node, const char* sep)
|
||||
{
|
||||
int slen,i,len,first,seplen;
|
||||
char* pathname;
|
||||
@ -366,17 +365,17 @@ makeocpathstring3(OCconnection conn, OCobject node, const char* sep)
|
||||
len = nclistlength(ocpath);
|
||||
assert(len > 0); /* dataset at least */
|
||||
|
||||
oc_inq_type(conn,node,&octype);
|
||||
oc_dds_type(conn,node,&octype);
|
||||
if(octype == OC_Dataset)
|
||||
{pathname = nulldup(""); goto done;} /* Dataset */
|
||||
|
||||
seplen = strlen(sep);
|
||||
for(slen=0,i=0;i<len;i++) {
|
||||
OCobject node = (OCobject)nclistget(ocpath,i);
|
||||
OCddsnode node = (OCddsnode)nclistget(ocpath,i);
|
||||
char* name;
|
||||
oc_inq_type(conn,node,&octype);
|
||||
oc_dds_type(conn,node,&octype);
|
||||
if(octype == OC_Dataset) continue;
|
||||
oc_inq_name(conn,node,&name);
|
||||
oc_dds_name(conn,node,&name);
|
||||
slen += (name == NULL? 0 : strlen(name));
|
||||
slen += seplen;
|
||||
nullfree(name);
|
||||
@ -386,11 +385,11 @@ makeocpathstring3(OCconnection conn, OCobject node, const char* sep)
|
||||
MEMCHECK(pathname,NULL);
|
||||
pathname[0] = '\0';
|
||||
for(first=1,i=0;i<len;i++) {
|
||||
OCobject node = (OCobject)nclistget(ocpath,i);
|
||||
OCddsnode node = (OCddsnode)nclistget(ocpath,i);
|
||||
char* name;
|
||||
oc_inq_type(conn,node,&octype);
|
||||
oc_dds_type(conn,node,&octype);
|
||||
if(octype == OC_Dataset) continue;
|
||||
oc_inq_name(conn,node,&name);
|
||||
oc_dds_name(conn,node,&name);
|
||||
if(!first) strcat(pathname,sep);
|
||||
if(name != NULL) strcat(pathname,name);
|
||||
nullfree(name);
|
||||
@ -688,8 +687,8 @@ deltatime()
|
||||
|
||||
/* Provide a wrapper for oc_fetch so we can log what it does */
|
||||
OCerror
|
||||
dap_fetch(NCDAPCOMMON* nccomm, OCconnection conn, const char* ce,
|
||||
OCdxd dxd, OCobject* rootp)
|
||||
dap_fetch(NCDAPCOMMON* nccomm, OClink conn, const char* ce,
|
||||
OCdxd dxd, OCddsnode* rootp)
|
||||
{
|
||||
OCerror ocstat;
|
||||
char* ext;
|
||||
@ -714,15 +713,15 @@ dap_fetch(NCDAPCOMMON* nccomm, OCconnection conn, const char* ce,
|
||||
/* Build uri string minus the constraint */
|
||||
char* baseurl = nc_uribuild(nccomm->oc.url,NULL,ext,0);
|
||||
if(ce == NULL)
|
||||
LOG1(NCLOGNOTE,"fetch: %s\n",baseurl);
|
||||
LOG1(NCLOGNOTE,"fetch: %s",baseurl);
|
||||
else
|
||||
LOG2(NCLOGNOTE,"fetch: %s?%s\n",baseurl,ce);
|
||||
LOG2(NCLOGNOTE,"fetch: %s?%s",baseurl,ce);
|
||||
nullfree(baseurl);
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
gettimeofday(&time0,NULL);
|
||||
#endif
|
||||
}
|
||||
ocstat = oc_fetchf(conn,ce,dxd,flags,rootp);
|
||||
ocstat = oc_fetch(conn,ce,dxd,flags,rootp);
|
||||
if(FLAGSET(nccomm->controls,NCF_SHOWFETCH)) {
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
double secs;
|
||||
|
@ -27,13 +27,13 @@ extern char* nctypetostring(nc_type);
|
||||
extern char* maketmppath(char* path, char* prefix);
|
||||
|
||||
extern void collectnodepath3(struct CDFnode*, NClist* path, int dataset);
|
||||
extern void collectocpath(OCconnection conn, OCobject node, NClist* path);
|
||||
extern void collectocpath(OClink conn, OCobject node, NClist* path);
|
||||
|
||||
extern char* makecdfpathstring3(struct CDFnode*,const char*);
|
||||
extern void clonenodenamepath3(struct CDFnode*, NClist*, int);
|
||||
extern char* makepathstring3(NClist* path, const char* separator, int flags);
|
||||
|
||||
extern char* makeocpathstring3(OCconnection, OCobject, const char*);
|
||||
extern char* makeocpathstring3(OClink, OCobject, const char*);
|
||||
|
||||
extern char* cdflegalname3(char* dapname);
|
||||
|
||||
@ -78,7 +78,7 @@ extern int nc__testurl(const char* parth, char** basename);
|
||||
|
||||
|
||||
/* Provide a wrapper for oc_fetch so we can log what it does */
|
||||
extern OCerror dap_fetch(struct NCDAPCOMMON*,OCconnection,const char*,OCdxd,OCobject*);
|
||||
extern OCerror dap_fetch(struct NCDAPCOMMON*,OClink,const char*,OCdxd,OCobject*);
|
||||
|
||||
extern int dap_badname(char* name);
|
||||
extern char* dap_repairname(char* name);
|
||||
|
@ -22,12 +22,19 @@
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#define LBRACE "{"
|
||||
#define RBRACE "}"
|
||||
|
||||
int dceverbose = 0;
|
||||
|
||||
static char* opstrings[] = OPSTRINGS ;
|
||||
|
||||
static void ceallnodesr(DCEnode* node, NClist* allnodes, CEsort which);
|
||||
static void dcedump(DCEnode* node, NCbytes* buf);
|
||||
static void dcedumpraw(DCEnode* node, NCbytes* buf);
|
||||
static void dcedumprawlist(NClist* list, NCbytes* buf);
|
||||
|
||||
#if 0 /*not currently used */
|
||||
/* Parse incoming url constraints, if any,
|
||||
to check for syntactic correctness
|
||||
*/
|
||||
@ -54,6 +61,7 @@ fprintf(stderr,"constraint: %s",dcetostring((DCEnode*)dapconstraint));
|
||||
#endif
|
||||
return ncstat;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Worksheet
|
||||
|
||||
@ -154,6 +162,7 @@ dceslicemerge(DCEslice* dst, DCEslice* src)
|
||||
Given two projection lists, merge
|
||||
src into dst taking
|
||||
overlapping projections into acct.
|
||||
Dst will be modified.
|
||||
*/
|
||||
int
|
||||
dcemergeprojectionlists(NClist* dst, NClist* src)
|
||||
@ -479,6 +488,29 @@ dcetostring(DCEnode* node)
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Mostly for debugging */
|
||||
char*
|
||||
dcerawtostring(void* node)
|
||||
{
|
||||
char* s;
|
||||
NCbytes* buf = ncbytesnew();
|
||||
dcedumpraw((DCEnode*)node,buf);
|
||||
s = ncbytesextract(buf);
|
||||
ncbytesfree(buf);
|
||||
return s;
|
||||
}
|
||||
|
||||
char*
|
||||
dcerawlisttostring(NClist* list)
|
||||
{
|
||||
char* s;
|
||||
NCbytes* buf = ncbytesnew();
|
||||
dcedumprawlist(list,buf);
|
||||
s = ncbytesextract(buf);
|
||||
ncbytesfree(buf);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* For debugging */
|
||||
#ifdef DEBUG
|
||||
static char*
|
||||
@ -500,6 +532,12 @@ dimdecl(size_t declsize)
|
||||
|
||||
void
|
||||
dcetobuffer(DCEnode* node, NCbytes* buf)
|
||||
{
|
||||
dcedump(node,buf);
|
||||
}
|
||||
|
||||
static void
|
||||
dcedump(DCEnode* node, NCbytes* buf)
|
||||
{
|
||||
int i;
|
||||
char tmp[1024];
|
||||
@ -864,3 +902,246 @@ dcesamepath(NClist* list1, NClist* list2)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dcesegment_transpose(DCEsegment* segment,
|
||||
size_t* start,
|
||||
size_t* count,
|
||||
size_t* stride,
|
||||
size_t* sizes
|
||||
)
|
||||
{
|
||||
int i;
|
||||
if(segment != NULL && sizes != NULL) {
|
||||
for(i=0;i<segment->rank;i++) {
|
||||
if(start != NULL) start[i] = segment->slices[i].first;
|
||||
if(count != NULL) count[i] = segment->slices[i].count;
|
||||
if(stride != NULL) stride[i] = (size_t)segment->slices[i].stride;
|
||||
if(sizes != NULL) sizes[i] = segment->slices[i].declsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute segment size for subset of slices */
|
||||
size_t
|
||||
dcesegmentsize(DCEsegment* seg, size_t start, size_t stop)
|
||||
{
|
||||
int i, count;
|
||||
if(!seg->slicesdefined) return 0; /* actually, we don't know */
|
||||
for(count=1,i=start;i<stop;i++) {
|
||||
count *= seg->slices[i].count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Return the index of the leftmost slice
|
||||
starting at start and upto, but not including
|
||||
stop, such that it and all slices to the right
|
||||
are "safe". Safe means dceiswholeslice() is true.
|
||||
In effect, we can read the safe index set as a
|
||||
single chunk. Return stop if there is no safe index.
|
||||
*/
|
||||
|
||||
size_t
|
||||
dcesafeindex(DCEsegment* seg, size_t start, size_t stop)
|
||||
{
|
||||
size_t safe;
|
||||
if(!seg->slicesdefined) return stop; /* actually, we don't know */
|
||||
if(stop == 0) return stop;
|
||||
/* watch out because safe is unsigned */
|
||||
for(safe=stop-1;safe>start;safe--) {
|
||||
if(!dceiswholeslice(&seg->slices[safe])) return safe+1;
|
||||
}
|
||||
return dceiswholeslice(&seg->slices[start]) ? start /*every slice is safe*/
|
||||
: start+1 ;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
dcesortname(CEsort sort)
|
||||
{
|
||||
switch (sort) {
|
||||
case CES_SLICE: return "SLICE";
|
||||
case CES_SEGMENT: return "SEGMENT";
|
||||
case CES_VAR: return "VAR";
|
||||
case CES_FCN: return "FCN";
|
||||
case CES_CONST: return "CONST";
|
||||
case CES_VALUE: return "VALUE";
|
||||
case CES_PROJECT: return "PROJECT";
|
||||
case CES_SELECT: return "SELECT";
|
||||
case CES_CONSTRAINT: return "CONSTRAINT";
|
||||
case CES_STR: return "STR";
|
||||
case CES_INT: return "INT";
|
||||
case CES_FLOAT: return "FLOAT";
|
||||
default: break;
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
static void
|
||||
dcedumpraw(DCEnode* node, NCbytes* buf)
|
||||
{
|
||||
int i;
|
||||
char tmp[1024];
|
||||
|
||||
if(buf == NULL) return;
|
||||
if(node == NULL) {ncbytescat(buf,"<null>"); return;}
|
||||
|
||||
ncbytescat(buf,LBRACE);
|
||||
ncbytescat(buf,(char*)dcesortname(node->sort));
|
||||
|
||||
switch (node->sort) {
|
||||
|
||||
case CES_SLICE: {
|
||||
DCEslice* slice = (DCEslice*)node;
|
||||
snprintf(tmp,sizeof(tmp),
|
||||
" [first=%lu count=%lu stride=%lu len=%lu stop=%lu size=%lu]",
|
||||
(unsigned long)slice->first,
|
||||
(unsigned long)slice->count,
|
||||
(unsigned long)slice->stride,
|
||||
(unsigned long)slice->length,
|
||||
(unsigned long)slice->stop,
|
||||
(unsigned long)slice->declsize);
|
||||
ncbytescat(buf,tmp);
|
||||
} break;
|
||||
|
||||
case CES_SEGMENT: {
|
||||
DCEsegment* segment = (DCEsegment*)node;
|
||||
int rank = segment->rank;
|
||||
char* name = (segment->name?segment->name:"<unknown>");
|
||||
ncbytescat(buf," name=");
|
||||
ncbytescat(buf,name);
|
||||
snprintf(tmp,sizeof(tmp)," rank=%lu",(unsigned long)rank);
|
||||
ncbytescat(buf,tmp);
|
||||
ncbytescat(buf," defined=");
|
||||
ncbytescat(buf,(segment->slicesdefined?"1":"0"));
|
||||
ncbytescat(buf," declized=");
|
||||
ncbytescat(buf,(segment->slicesdeclized?"1":"0"));
|
||||
if(rank > 0) {
|
||||
ncbytescat(buf," slices=");
|
||||
for(i=0;i<rank;i++) {
|
||||
DCEslice* slice = segment->slices+i;
|
||||
dcedumpraw((DCEnode*)slice,buf);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case CES_VAR: {
|
||||
DCEvar* var = (DCEvar*)node;
|
||||
ncbytescat(buf," segments=");
|
||||
dcedumprawlist(var->segments,buf);
|
||||
} break;
|
||||
|
||||
case CES_FCN: {
|
||||
DCEfcn* fcn = (DCEfcn*)node;
|
||||
ncbytescat(buf," name=");
|
||||
ncbytescat(buf,fcn->name);
|
||||
ncbytescat(buf,"args=");
|
||||
dcedumprawlist(fcn->args,buf);
|
||||
} break;
|
||||
|
||||
case CES_CONST: {
|
||||
DCEconstant* value = (DCEconstant*)node;
|
||||
ncbytescat(buf," discrim=");
|
||||
ncbytescat(buf,dcesortname(value->discrim));
|
||||
ncbytescat(buf," value=");
|
||||
switch (value->discrim) {
|
||||
case CES_STR:
|
||||
ncbytescat(buf,"|");
|
||||
ncbytescat(buf,value->text);
|
||||
ncbytescat(buf,"|");
|
||||
break;
|
||||
case CES_INT:
|
||||
snprintf(tmp,sizeof(tmp),"%lld",value->intvalue);
|
||||
ncbytescat(buf,tmp);
|
||||
break;
|
||||
case CES_FLOAT:
|
||||
snprintf(tmp,sizeof(tmp),"%g",value->floatvalue);
|
||||
ncbytescat(buf,tmp);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CES_VALUE: {
|
||||
DCEvalue* value = (DCEvalue*)node;
|
||||
ncbytescat(buf," discrim=");
|
||||
ncbytescat(buf,dcesortname(value->discrim));
|
||||
switch (value->discrim) {
|
||||
case CES_CONST:
|
||||
dcedumpraw((DCEnode*)value->constant,buf);
|
||||
break;
|
||||
case CES_VAR:
|
||||
dcedumpraw((DCEnode*)value->var,buf);
|
||||
break;
|
||||
case CES_FCN:
|
||||
dcedumpraw((DCEnode*)value->fcn,buf);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CES_PROJECT: {
|
||||
DCEprojection* target = (DCEprojection*)node;
|
||||
ncbytescat(buf," discrim=");
|
||||
ncbytescat(buf,dcesortname(target->discrim));
|
||||
switch (target->discrim) {
|
||||
case CES_VAR:
|
||||
dcedumpraw((DCEnode*)target->var,buf);
|
||||
break;
|
||||
case CES_FCN:
|
||||
dcedumpraw((DCEnode*)target->fcn,buf);
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CES_SELECT: {
|
||||
DCEselection* sel = (DCEselection*)node;
|
||||
ncbytescat(buf," ");
|
||||
dcedumpraw((DCEnode*)sel->lhs,buf);
|
||||
if(sel->operator == CES_NIL) break;
|
||||
ncbytescat(buf,opstrings[(int)sel->operator]);
|
||||
if(nclistlength(sel->rhs) > 1)
|
||||
ncbytescat(buf,"{");
|
||||
dcedumprawlist(sel->rhs,buf);
|
||||
if(nclistlength(sel->rhs) > 1)
|
||||
ncbytescat(buf,"}");
|
||||
} break;
|
||||
|
||||
case CES_CONSTRAINT: {
|
||||
DCEconstraint* con = (DCEconstraint*)node;
|
||||
if(con->projections != NULL && nclistlength(con->projections) > 0) {
|
||||
ncbytescat(buf,"projections=");
|
||||
dcedumprawlist(con->projections,buf);
|
||||
}
|
||||
if(con->selections != NULL && nclistlength(con->selections) > 0) {
|
||||
ncbytescat(buf,"selections=");
|
||||
dcedumprawlist(con->selections,buf);
|
||||
}
|
||||
} break;
|
||||
|
||||
case CES_NIL: {
|
||||
ncbytescat(buf,"<nil>");
|
||||
} break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
ncbytescat(buf,RBRACE);
|
||||
}
|
||||
|
||||
static void
|
||||
dcedumprawlist(NClist* list, NCbytes* buf)
|
||||
{
|
||||
int i;
|
||||
if(list == NULL || buf == NULL) return;
|
||||
ncbytescat(buf,"(");
|
||||
for(i=0;i<nclistlength(list);i++) {
|
||||
DCEnode* node = (DCEnode*)nclistget(list,i);
|
||||
if(node == NULL) continue;
|
||||
if(i>0) ncbytescat(buf,",");
|
||||
dcedumpraw((DCEnode*)node,buf);
|
||||
}
|
||||
ncbytescat(buf,")");
|
||||
}
|
||||
|
@ -102,6 +102,8 @@ extern char* dcetostring(DCEnode* node);
|
||||
extern char* dcelisttostring(NClist* list,char*);
|
||||
extern void dcetobuffer(DCEnode* node, NCbytes* buf);
|
||||
extern void dcelisttobuffer(NClist* list, NCbytes* buf,char*);
|
||||
extern char* dcerawtostring(void*);
|
||||
extern char* dcerawlisttostring(NClist*);
|
||||
|
||||
extern NClist* dceallnodes(DCEnode* node, CEsort which);
|
||||
|
||||
@ -117,6 +119,23 @@ extern int dceiswholeprojection(DCEprojection*);
|
||||
extern int dcesamepath(NClist* list1, NClist* list2);
|
||||
extern int dcemergeprojections(DCEprojection* dst, DCEprojection* src);
|
||||
|
||||
extern void dcesegment_transpose(DCEsegment* seg,
|
||||
size_t* start,
|
||||
size_t* count,
|
||||
size_t* stride,
|
||||
size_t* sizes
|
||||
);
|
||||
|
||||
|
||||
/* Find leftmost index of segment slices
|
||||
s.t. that index and all upto last
|
||||
satisfy dceiswholeslice
|
||||
*/
|
||||
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);
|
||||
|
||||
extern int dceverbose;
|
||||
|
||||
#endif /*DCECONSTRAINTS_H*/
|
||||
|
42
libdap2/env
42
libdap2/env
@ -1,21 +1,43 @@
|
||||
TOPDIR="/home/dmh/svn/trunk"
|
||||
PARMS=""; ARGS=""; CON="" ; CE=""; OCON="" ; VAR=""
|
||||
alias q0=;alias qq=;alias qv=;alias q=;alias qh=;alias qqh=;alias qall=;alias qv=;alias qo=;
|
||||
|
||||
TOP="/home/dmh/mach/major"
|
||||
|
||||
PROG=./ncd
|
||||
#PROG="$TOP/ncdump/ncdump"
|
||||
|
||||
P=`pwd`
|
||||
|
||||
T="synth1"
|
||||
|
||||
F="file://$TOP/ncdap_test/testdata3/$T"
|
||||
#F="http://motherlode.ucar.edu:8081/dts/$T"
|
||||
#F="http://motherlode.ucar.edu:8080/thredds/dodsC/testdods/coads_climatology.nc"
|
||||
|
||||
PARMS="[log]"
|
||||
#PARMS="${PARMS}[netcdf3]"
|
||||
#PARMS="${PARMS}[fetch=disk]"
|
||||
#PARMS="${PARMS}[cache]"
|
||||
PARMS="${PARMS}[cache]"
|
||||
#PARMS="${PARMS}[prefetch]"
|
||||
#PARMS="${PARMS}[nocache]"
|
||||
#PARMS="${PARMS}[noprefetch]"
|
||||
#PARMS="${PARMS}[wholevar]"
|
||||
#PARMS="${PARMS}[show=fetch]"
|
||||
|
||||
F="file://${TOPDIR}/ncdap_test/testdata3/synth1"
|
||||
#F="http://motherlode.ucar.edu:8081/dts/test.02"
|
||||
#F="http://motherlode.ucar.edu:8080/thredds/dodsC/testdods/coads_climatology.nc"
|
||||
# Pick in order
|
||||
if test "x$PROG" = x ; then
|
||||
for f in ../ncdump/.libs/lt-ncdump ../ncdump/.libs/ncdump ../ncdump/ncdump ./ncd ; do
|
||||
if test -f $f ; then
|
||||
PROG="$f"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test "x$PROG" = x ; then
|
||||
echo "cannot locate ncdump; defaulting"
|
||||
PROG="../ncdump/ncdump"
|
||||
fi
|
||||
|
||||
PROG="./ncd"
|
||||
#PROG="../ncdump/ncdump"
|
||||
U="${PARMS}$F"
|
||||
if test "x$CON" != "x" ; then U="${PARMS}$F?$CON"; fi
|
||||
UALL="${PARMS}$F"
|
||||
@ -27,6 +49,7 @@ fi
|
||||
#ARGS="-c $ARGS"
|
||||
|
||||
VARGS="--leak-check=full"
|
||||
|
||||
alias qq="gdb --args $PROG $ARGS '$U'"
|
||||
alias qv="valgrind $VARGS PROG $ARGS '$U'"
|
||||
alias q0="$PROG $ARGS '$U'"
|
||||
@ -60,8 +83,8 @@ F="http://motherlode.ucar.edu:8080/thredds/dodsC/testdods/in.nc"
|
||||
F="http://ceda.ac.uk/dap/neodc/casix/seawifs_plankton/data/monthly/PSC_monthly_1998.nc"
|
||||
F="http://test.opendap.org:8080/dods/dts/test.02"
|
||||
F="http://test.opendap.org/opendap/data/nc/coads_climatology.nc"
|
||||
F="file://${TOPDIR}/ncdap_test/testdata3/test.PointFile"
|
||||
F="file://${TOPDIR}/ncdap_test/testdata3/synth1"
|
||||
F="file://${TOP}/ncdap_test/testdata3/test.PointFile"
|
||||
F="file://${TOP}/ncdap_test/testdata3/synth1"
|
||||
F="http://dods.ndbc.noaa.gov/thredds/dodsC/data/stdmet/46029/46029h9999.nc"
|
||||
CON="wind_dir[1:10][0:0][0:0]"
|
||||
F="http://nomads.ncep.noaa.gov:9090/dods/gens/gens20111011/gep20_00z"
|
||||
@ -73,3 +96,4 @@ F="http://nomad1.ncep.noaa.gov:9090/dods/reanalyses/reanalysis-1/6hr/pgb/pgb"
|
||||
VAR=hgtprs
|
||||
fi
|
||||
|
||||
|
||||
|
@ -8,13 +8,14 @@
|
||||
#include "dapodom.h"
|
||||
#include "dapdump.h"
|
||||
#include "ncd3dispatch.h"
|
||||
|
||||
#include "ocx.h"
|
||||
|
||||
#define NEWVARM
|
||||
|
||||
static DCEnode* save = NULL;
|
||||
|
||||
/* Define a tracker for memory to support*/
|
||||
/* the concatenation*/
|
||||
|
||||
struct NCMEMORY {
|
||||
void* memory;
|
||||
char* next; /* where to store the next chunk of data*/
|
||||
@ -22,17 +23,20 @@ struct NCMEMORY {
|
||||
|
||||
/* Forward:*/
|
||||
static NCerror moveto(NCDAPCOMMON*, Getvara*, CDFnode* dataroot, void* memory);
|
||||
static NCerror movetor(NCDAPCOMMON*, OCdata currentcontent,
|
||||
static NCerror movetor(NCDAPCOMMON*, OCdatanode currentcontent,
|
||||
NClist* path, int depth,
|
||||
Getvara*, int dimindex,
|
||||
Getvara*, size_t dimindex,
|
||||
struct NCMEMORY*, NClist* segments);
|
||||
static NCerror movetofield(NCDAPCOMMON*, OCdatanode,
|
||||
NClist*, int depth,
|
||||
Getvara*, size_t dimindex,
|
||||
struct NCMEMORY*, NClist* segments);
|
||||
|
||||
static int findfield(CDFnode* node, CDFnode* subnode);
|
||||
static int wholeslicepoint(Dapodometer* odom);
|
||||
static NCerror removepseudodims(DCEprojection* proj);
|
||||
|
||||
static int extract(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*);
|
||||
static int extractstring(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*);
|
||||
static int extract(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, size_t dimindex, OClink, OCdatanode, struct NCMEMORY*);
|
||||
static int extractstring(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, size_t dimindex, OClink, OCdatanode, struct NCMEMORY*);
|
||||
|
||||
/**
|
||||
1. We build the projection to be sent to the server aka
|
||||
@ -53,7 +57,9 @@ but will use different fetch projections.
|
||||
a. URL is unconstrainable (e.g. file://...):
|
||||
fetchprojection = null => fetch whole dataset
|
||||
b. The target variable (as specified in nc_get_vara())
|
||||
is already in the cache and is whole variable.
|
||||
is already in the cache and is whole variable, but note
|
||||
that it might be part of the prefetch mixed in with other prefetched
|
||||
variables.
|
||||
fetchprojection = N.A. since variable is in the cache
|
||||
c. Vara is requesting part of a variable but NCF_WHOLEVAR flag is set.
|
||||
fetchprojection = unsliced vara variable => fetch whole variable
|
||||
@ -63,7 +69,7 @@ d. Vara is requesting part of a variable and NCF_WHOLEVAR flag is not set.
|
||||
2. At this point, all or part of the target variable is available in the cache.
|
||||
|
||||
3. We build a projection to walk (guide) the use of the oc
|
||||
data procedures in extract the required data from the cache.
|
||||
data procedures to extract the required data from the cache.
|
||||
For cases a,b,c:
|
||||
walkprojection = merge(urlprojection,varaprojection)
|
||||
For case d:
|
||||
@ -75,7 +81,6 @@ d. Vara is requesting part of a variable and NCF_WHOLEVAR flag is not set.
|
||||
from the vara projection that will properly access the cached data.
|
||||
This walk projection shifts the merged projection so all slices
|
||||
start at 0 and have a stride of 1.
|
||||
|
||||
*/
|
||||
|
||||
NCerror
|
||||
@ -125,7 +130,7 @@ nc3d_getvarx(int ncid, int varid,
|
||||
for(i=0;i<nclistlength(varnodes);i++) {
|
||||
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
|
||||
if(node->array.basevar == NULL
|
||||
&& node->nctype == NC_Primitive
|
||||
&& node->nctype == NC_Atomic
|
||||
&& node->ncid == varid) {
|
||||
cdfvar = node;
|
||||
break;
|
||||
@ -221,7 +226,7 @@ fprintf(stderr,"\n");
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
|
||||
|
||||
state = 0;
|
||||
if(iscached(dapcomm,cdfvar,&cachenode)) {
|
||||
if(iscached(dapcomm,cdfvar,&cachenode)) { /* ignores non-whole variable cache entries */
|
||||
state = CACHED;
|
||||
ASSERT((cachenode != NULL));
|
||||
#ifdef DEBUG
|
||||
@ -241,10 +246,11 @@ fprintf(stderr,"var is in cache\n");
|
||||
|
||||
ASSERT(state != 0);
|
||||
|
||||
/* Convert the start/stop/stride info into a projection */
|
||||
ncstat = buildvaraprojection3(varainfo,
|
||||
/* Compile the start/stop/stride info into a projection */
|
||||
ncstat = buildvaraprojection3(varainfo->target,
|
||||
startp,countp,stridep,
|
||||
&varaprojection);
|
||||
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
|
||||
|
||||
fetchprojection = NULL;
|
||||
@ -384,18 +390,16 @@ fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds));
|
||||
|
||||
/* Switch to datadds tree space*/
|
||||
varainfo->target = xtarget;
|
||||
save = (DCEnode*)varaprojection;
|
||||
ncstat = moveto(dapcomm,varainfo,varainfo->cache->datadds,data);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
|
||||
|
||||
goto ok;
|
||||
|
||||
fail:
|
||||
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
||||
ok:
|
||||
nclistfree(vars);
|
||||
dcefree((DCEnode*)varaprojection);
|
||||
dcefree((DCEnode*)fetchconstraint);
|
||||
freegetvara(varainfo);
|
||||
fail:
|
||||
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
@ -426,9 +430,9 @@ moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCconnection conn = nccomm->oc.conn;
|
||||
OCdata xrootcontent;
|
||||
OCobject ocroot;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
OCdatanode xrootcontent;
|
||||
OCddsnode ocroot;
|
||||
NClist* path = nclistnew();
|
||||
struct NCMEMORY memstate;
|
||||
|
||||
@ -436,8 +440,7 @@ moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory)
|
||||
|
||||
/* Get the root content*/
|
||||
ocroot = xrootnode->tree->ocroot;
|
||||
xrootcontent = oc_data_new(conn);
|
||||
ocstat = oc_data_root(conn,ocroot,xrootcontent);
|
||||
ocstat = oc_data_getroot(conn,ocroot,&xrootcontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
|
||||
/* Remember: xgetvar->target is in DATADDS tree */
|
||||
@ -445,7 +448,6 @@ moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory)
|
||||
ncstat = movetor(nccomm,xrootcontent,
|
||||
path,0,xgetvar,0,&memstate,
|
||||
xgetvar->varaprojection->var->segments);
|
||||
|
||||
done:
|
||||
nclistfree(path);
|
||||
oc_data_free(conn,xrootcontent);
|
||||
@ -455,170 +457,132 @@ done:
|
||||
|
||||
static NCerror
|
||||
movetor(NCDAPCOMMON* nccomm,
|
||||
OCdata currentcontent,
|
||||
OCdatanode currentcontent,
|
||||
NClist* path,
|
||||
int depth, /* depth is position in segment list*/
|
||||
Getvara* xgetvar,
|
||||
int dimindex, /* dimindex is position in xgetvar->slices*/
|
||||
size_t dimindex, /* dimindex is position in xgetvar->slices*/
|
||||
struct NCMEMORY* memory,
|
||||
NClist* segments)
|
||||
{
|
||||
int i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
size_t fieldindex,gridindex,rank;
|
||||
OCconnection conn = nccomm->oc.conn;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
CDFnode* xnode = (CDFnode*)nclistget(path,depth);
|
||||
OCdata reccontent = OCNULL;
|
||||
OCdata dimcontent = OCNULL;
|
||||
OCdata fieldcontent = OCNULL;
|
||||
Dapodometer* odom = OCNULL;
|
||||
OCmode currentmode = OCNULLMODE;
|
||||
CDFnode* xnext;
|
||||
OCdatanode reccontent = NULL;
|
||||
OCdatanode dimcontent = NULL;
|
||||
OCdatanode fieldcontent = NULL;
|
||||
Dapodometer* odom = NULL;
|
||||
int hasstringdim = 0;
|
||||
size_t dimoffset;
|
||||
DCEsegment* segment;
|
||||
int newdepth;
|
||||
int caching = FLAGSET(nccomm->controls,NCF_CACHE);
|
||||
int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE);
|
||||
OCDT mode;
|
||||
|
||||
/* Note that we use depth-1 because the path contains the DATASET
|
||||
but the segment list does not */
|
||||
segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/
|
||||
if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1;
|
||||
|
||||
ocstat = oc_data_mode(conn,currentcontent,¤tmode);
|
||||
/* Get the mode */
|
||||
mode = oc_data_mode(conn,currentcontent);
|
||||
|
||||
#ifdef DEBUG2
|
||||
fprintf(stderr,"moveto: nctype=%d currentmode=%d depth=%d dimindex=%d",
|
||||
xnode->nctype, currentmode, depth,dimindex);
|
||||
fprintf(stderr,"moveto: nctype=%d depth=%d dimindex=%d mode=%s",
|
||||
xnode->nctype, depth,dimindex,oc_data_modestring(mode));
|
||||
fprintf(stderr," segment=%s hasstringdim=%d\n",
|
||||
dcetostring((DCEnode*)segment),hasstringdim);
|
||||
#endif
|
||||
|
||||
/* Switch on the combination of nctype and mode */
|
||||
#define CASE(nc1,nc2) (nc1*1024+nc2)
|
||||
switch (xnode->nctype) {
|
||||
|
||||
/* This must be consistent with the oc mode transition function */
|
||||
switch (CASE(xnode->nctype,currentmode)) {
|
||||
#if 0
|
||||
#define OCDT_FIELD ((OCDT)(1)) /* field of a container */
|
||||
#define OCDT_ELEMENT ((OCDT)(2)) /* element of a structure array */
|
||||
#define OCDT_RECORD ((OCDT)(4)) /* record of a sequence */
|
||||
#define OCDT_ARRAY ((OCDT)(8)) /* is structure array */
|
||||
#define OCDT_SEQUENCE ((OCDT)(16)) /* is sequence */
|
||||
#define OCDT_ATOMIC ((OCDT)(32)) /* is atomic leaf */
|
||||
#endif
|
||||
|
||||
default:
|
||||
PANIC2("Illegal combination: nctype=%d mode=%d",
|
||||
(int)xnode->nctype,(int)currentmode);
|
||||
break;
|
||||
goto done;
|
||||
|
||||
case CASE(NC_Sequence,OCFIELDMODE):
|
||||
case CASE(NC_Dataset,OCFIELDMODE):
|
||||
case CASE(NC_Grid,OCFIELDMODE):
|
||||
case CASE(NC_Structure,OCFIELDMODE):
|
||||
/* currentcontent points to the grid/dataset/structure instance */
|
||||
xnext = (CDFnode*)nclistget(path,depth+1);
|
||||
ASSERT((xnext != NULL));
|
||||
fieldindex = findfield(xnode,xnext);
|
||||
/* If the next node is a virtual node, then
|
||||
we need to effectively
|
||||
ignore it and use the appropriate subnode.
|
||||
If the next node is a structuregrid node, then
|
||||
use it as is.
|
||||
*/
|
||||
if(xnext->virtual) {
|
||||
CDFnode* xgrid = xnext;
|
||||
xnext = (CDFnode*)nclistget(path,depth+2); /* real node */
|
||||
gridindex = fieldindex;
|
||||
fieldindex = findfield(xgrid,xnext);
|
||||
fieldindex += gridindex;
|
||||
newdepth = depth+2;
|
||||
} else {
|
||||
newdepth = depth+1;
|
||||
}
|
||||
fieldcontent = oc_data_new(conn);
|
||||
ocstat = oc_data_ith(conn,currentcontent,fieldindex,fieldcontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
|
||||
ncstat = movetor(nccomm,fieldcontent,
|
||||
path,newdepth,xgetvar,dimindex,memory,
|
||||
segments);
|
||||
break;
|
||||
|
||||
case CASE(NC_Sequence,OCARRAYMODE): /* will actually always be scalar, but will have
|
||||
rank == 1 to account for the sequence dim */
|
||||
case CASE(NC_Grid,OCARRAYMODE): /* will actually always be scalar */
|
||||
case CASE(NC_Structure,OCARRAYMODE):
|
||||
/* figure out which slices refer to this node:
|
||||
dimindex upto dimindex+rank; */
|
||||
ASSERT((segment != NULL));
|
||||
rank = segment->rank;
|
||||
if(xnode->nctype == NC_Sequence)
|
||||
rank--; /* ignore the sequence dim */
|
||||
if(rank == 0) {
|
||||
odom = newdapodometer1(1);
|
||||
} else if(caching || unconstrainable) {
|
||||
odom = newdapodometer(segment->slices,0,rank);
|
||||
} else { /*Since vara was projected out, build a simple odometer*/
|
||||
odom = newsimpledapodometer(segment,rank);
|
||||
}
|
||||
while(dapodometermore(odom)) {
|
||||
OCmode mode;
|
||||
/* Compute which instance to move to*/
|
||||
dimoffset = dapodometercount(odom);
|
||||
dimcontent = oc_data_new(conn);
|
||||
ocstat = oc_data_ith(conn,currentcontent,dimoffset,dimcontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
|
||||
ocstat = oc_data_mode(conn,dimcontent,&mode);
|
||||
ASSERT((mode == OCFIELDMODE
|
||||
|| (mode == OCSEQUENCEMODE && xnode->nctype == NC_Sequence)));
|
||||
ncstat = movetor(nccomm,dimcontent,
|
||||
path,depth,
|
||||
xgetvar,dimindex+rank,
|
||||
case NC_Grid:
|
||||
case NC_Dataset:
|
||||
case NC_Structure:
|
||||
/* Separate out the case where structure is dimensioned */
|
||||
if(oc_data_indexable(conn,currentcontent)) {
|
||||
/* => dimensioned structure */
|
||||
/* The current segment should reflect the
|
||||
proper parts of the nc_get_vara argument
|
||||
*/
|
||||
/* Create odometer for this structure's part of the projection */
|
||||
odom = dapodom_fromsegment(segment,0,segment->rank);
|
||||
while(dapodom_more(odom)) {
|
||||
/* Compute which instance to move to*/
|
||||
ocstat = oc_data_ithelement(conn,currentcontent,
|
||||
odom->index,&dimcontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
ASSERT(oc_data_indexed(conn,dimcontent));
|
||||
ncstat = movetor(nccomm,dimcontent,
|
||||
path,depth,/*keep same depth*/
|
||||
xgetvar,dimindex+segment->rank,
|
||||
memory,segments);
|
||||
dapodometerincr(odom);
|
||||
}
|
||||
freedapodometer(odom);
|
||||
break;
|
||||
|
||||
case CASE(NC_Sequence,OCSEQUENCEMODE): {
|
||||
DCEslice* uslice;
|
||||
ASSERT((segment != NULL));
|
||||
/* Get and check the corresponding sequence dimension from DDS */
|
||||
ASSERT((xnode->attachment != NULL));
|
||||
/* use uslice to walk the sequence; however, watch out
|
||||
for the case when the user set a limit and that limit
|
||||
is not actually reached in this request.
|
||||
*/
|
||||
/* By construction, this sequence represents the first
|
||||
(and only) dimension of this segment */
|
||||
uslice = &segment->slices[0];
|
||||
reccontent = oc_data_new(conn);
|
||||
for(i=uslice->first;i<uslice->stop;i+=uslice->stride) {
|
||||
OCmode eos;
|
||||
ocstat = oc_data_ith(conn,currentcontent,i,reccontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
|
||||
ocstat = oc_data_mode(conn,reccontent,&eos);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
|
||||
if(eos == OCNULLMODE) {
|
||||
/* We asked for too much */
|
||||
ncstat = THROW(NC_EINVALCOORDS);
|
||||
goto fail;
|
||||
dapodom_next(odom);
|
||||
}
|
||||
ncstat = movetor(nccomm,reccontent,
|
||||
path,depth,
|
||||
xgetvar,dimindex+1,
|
||||
memory,segments);
|
||||
if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto fail;}
|
||||
}
|
||||
} break;
|
||||
dapodom_free(odom);
|
||||
} else {/* scalar instance */
|
||||
ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
} break;
|
||||
|
||||
case NC_Sequence:
|
||||
if(fIsSet(mode,OCDT_SEQUENCE)) {
|
||||
ASSERT((xnode->attachment != NULL));
|
||||
ASSERT((segment != NULL));
|
||||
ASSERT((segment->rank == 1));
|
||||
/* Build an odometer for walking the sequence,
|
||||
however, watch out
|
||||
for the case when the user set a limit and that limit
|
||||
is not actually reached in this request.
|
||||
*/
|
||||
/* By construction, this sequence represents the first
|
||||
(and only) dimension of this segment */
|
||||
odom = dapodom_fromsegment(segment,0,1);
|
||||
while(dapodom_more(odom)) {
|
||||
size_t recordindex = dapodom_count(odom);
|
||||
ocstat = oc_data_ithrecord(conn,currentcontent,
|
||||
recordindex,&reccontent);
|
||||
if(ocstat != OC_NOERR) {
|
||||
if(ocstat == OC_EINDEX)
|
||||
ocstat = OC_EINVALCOORDS;
|
||||
THROWCHK(ocstat); goto done;
|
||||
}
|
||||
ncstat = movetor(nccomm,reccontent,
|
||||
path,depth,
|
||||
xgetvar,dimindex+1,
|
||||
memory,segments);
|
||||
if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
dapodom_next(odom);
|
||||
}
|
||||
} else if(fIsSet(mode,OCDT_RECORD)) {
|
||||
/* Treat like structure */
|
||||
/* currentcontent points to the record instance */
|
||||
ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
}
|
||||
break;
|
||||
|
||||
case NC_Atomic:
|
||||
|
||||
case CASE(NC_Primitive,OCPRIMITIVEMODE):
|
||||
if(hasstringdim)
|
||||
ncstat = extractstring(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory);
|
||||
ncstat = extractstring(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory);
|
||||
else
|
||||
ncstat = extract(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory);
|
||||
ncstat = extract(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory);
|
||||
break;
|
||||
|
||||
}
|
||||
goto ok;
|
||||
|
||||
fail:
|
||||
ok:
|
||||
done:
|
||||
oc_data_free(conn,dimcontent);
|
||||
oc_data_free(conn,fieldcontent);
|
||||
oc_data_free(conn,reccontent);
|
||||
@ -626,6 +590,63 @@ ok:
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
static NCerror
|
||||
movetofield(NCDAPCOMMON* nccomm,
|
||||
OCdatanode currentcontent,
|
||||
NClist* path,
|
||||
int depth, /* depth is position in segment list*/
|
||||
Getvara* xgetvar,
|
||||
size_t dimindex, /* dimindex is position in xgetvar->slices*/
|
||||
struct NCMEMORY* memory,
|
||||
NClist* segments)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
size_t fieldindex,gridindex;
|
||||
OClink conn = nccomm->oc.conn;
|
||||
CDFnode* xnode = (CDFnode*)nclistget(path,depth);
|
||||
OCdatanode reccontent = NULL;
|
||||
OCdatanode dimcontent = NULL;
|
||||
OCdatanode fieldcontent = NULL;
|
||||
CDFnode* xnext;
|
||||
int newdepth;
|
||||
|
||||
/* currentcontent points to the grid/dataset/structure/record instance */
|
||||
xnext = (CDFnode*)nclistget(path,depth+1);
|
||||
ASSERT((xnext != NULL));
|
||||
fieldindex = findfield(xnode,xnext);
|
||||
/* If the next node is a virtual node, then
|
||||
we need to effectively
|
||||
ignore it and use the appropriate subnode.
|
||||
If the next node is a structuregrid node, then
|
||||
use it as is.
|
||||
*/
|
||||
if(xnext->virtual) {
|
||||
CDFnode* xgrid = xnext;
|
||||
xnext = (CDFnode*)nclistget(path,depth+2); /* real node */
|
||||
gridindex = fieldindex;
|
||||
fieldindex = findfield(xgrid,xnext);
|
||||
fieldindex += gridindex;
|
||||
newdepth = depth+2;
|
||||
} else {
|
||||
newdepth = depth+1;
|
||||
}
|
||||
/* Move to appropriate field */
|
||||
ocstat = oc_data_ithfield(conn,currentcontent,fieldindex,&fieldcontent);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
ncstat = movetor(nccomm,fieldcontent,
|
||||
path,newdepth,xgetvar,dimindex,memory,
|
||||
segments);
|
||||
|
||||
done:
|
||||
oc_data_free(conn,dimcontent);
|
||||
oc_data_free(conn,fieldcontent);
|
||||
oc_data_free(conn,reccontent);
|
||||
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Determine the index in the odometer at which
|
||||
the odometer will be walking the whole subslice
|
||||
This will allow us to optimize.
|
||||
@ -636,9 +657,9 @@ wholeslicepoint(Dapodometer* odom)
|
||||
unsigned int i;
|
||||
int point;
|
||||
for(point=-1,i=0;i<odom->rank;i++) {
|
||||
ASSERT((odom->slices[i].declsize != 0));
|
||||
if(odom->slices[i].first != 0 || odom->slices[i].stride != 1
|
||||
|| odom->slices[i].length != odom->slices[i].declsize)
|
||||
ASSERT((odom->size[i] != 0));
|
||||
if(odom->start[i] != 0 || odom->stride[i] != 1
|
||||
|| odom->count[i] != odom->size[i])
|
||||
point = i;
|
||||
}
|
||||
if(point == -1)
|
||||
@ -649,6 +670,7 @@ wholeslicepoint(Dapodometer* odom)
|
||||
point += 1; /* intermediate point */
|
||||
return point;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
findfield(CDFnode* node, CDFnode* field)
|
||||
@ -704,7 +726,7 @@ nc3d_getvarmx(int ncid, int varid,
|
||||
for(i=0;i<nclistlength(varnodes);i++) {
|
||||
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
|
||||
if(node->array.basevar == NULL
|
||||
&& node->nctype == NC_Primitive
|
||||
&& node->nctype == NC_Atomic
|
||||
&& node->ncid == varid) {
|
||||
cdfvar = node;
|
||||
break;
|
||||
@ -716,8 +738,7 @@ nc3d_getvarmx(int ncid, int varid,
|
||||
|
||||
if(nclistlength(cdfvar->array.dimsetplus) == 0) {
|
||||
/* The variable is a scalar; consequently, there is only one
|
||||
thing to get and only one place to put it. (Why was I
|
||||
called?) */
|
||||
thing to get and only one place to put it. */
|
||||
/* recurse with additional parameters */
|
||||
return THROW(nc3d_getvarx(ncid,varid,
|
||||
NULL,NULL,NULL,
|
||||
@ -797,11 +818,12 @@ nc3d_getvarmx(int ncid, int varid,
|
||||
default: break;
|
||||
}
|
||||
|
||||
odom = newdapodometer2(start,edges,stride,0,ncrank);
|
||||
|
||||
odom = dapodom_new(ncrank,start,edges,stride,NULL);
|
||||
|
||||
/* Walk the local copy */
|
||||
for(i=0;i<nelems;i++) {
|
||||
size_t voffset = dapodometervarmcount(odom,map,dimsizes);
|
||||
size_t voffset = dapodom_varmcount(odom,map,dimsizes);
|
||||
void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
|
||||
char* localpos = (localcopy + externsize*i);
|
||||
/* extract the indexset'th value from local copy */
|
||||
@ -812,13 +834,13 @@ fprintf(stderr,"new: %lu -> %lu %f\n",
|
||||
(unsigned long)voffset,
|
||||
*(float*)localpos);
|
||||
*/
|
||||
dapodometerincr(odom);
|
||||
dapodom_next(odom);
|
||||
}
|
||||
#else
|
||||
odom = newdapodometer2(start,edges,stride,0,ncrank);
|
||||
while(dapodometermore(odom)) {
|
||||
size_t* indexset = dapodometerindices(odom);
|
||||
size_t voffset = dapodometervarmcount(odom,map,dimsizes);
|
||||
odom = dapodom_new(ncrank,start,edges,stride,NULL);
|
||||
while(dapodom_more(odom)) {
|
||||
size_t* indexset = odom->index;
|
||||
size_t voffset = dapodom_varmcount(odom,map,dimsizes);
|
||||
char internalmem[128];
|
||||
char externalmem[128];
|
||||
void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
|
||||
@ -832,11 +854,11 @@ fprintf(stderr,"new: %lu -> %lu %f\n",
|
||||
memcpy(dataoffset,(void*)externalmem,externsize);
|
||||
/*
|
||||
fprintf(stderr,"old: %lu -> %lu %f\n",
|
||||
(unsigned long)dapodometercount(odom),
|
||||
(unsigned long)dapodom_count(odom),
|
||||
(unsigned long)voffset,
|
||||
*(float*)externalmem);
|
||||
*/
|
||||
dapodometerincr(odom);
|
||||
dapodom_next(odom);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -869,8 +891,7 @@ conversionrequired(nc_type t1, nc_type t2)
|
||||
}
|
||||
|
||||
/* We are at a primitive variable or scalar that has no string dimensions.
|
||||
Extract the data.
|
||||
(This is way too complicated)
|
||||
Extract the data. (This is way too complicated)
|
||||
*/
|
||||
static int
|
||||
extract(
|
||||
@ -878,21 +899,18 @@ extract(
|
||||
Getvara* xgetvar,
|
||||
CDFnode* xnode,
|
||||
DCEsegment* segment,
|
||||
size_t dimindex,/*notused*/
|
||||
OClink conn,
|
||||
OCdata currentcontent,
|
||||
OCdatanode currentcontent,
|
||||
struct NCMEMORY* memory
|
||||
)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
size_t rank;
|
||||
Dapodometer* odom = OCNULL;
|
||||
int wholepoint;
|
||||
size_t count,rank0;
|
||||
Dapodometer* odom = NULL;
|
||||
size_t externtypesize;
|
||||
size_t interntypesize;
|
||||
char* localmemory = NULL;
|
||||
size_t odomsubsize;
|
||||
size_t internlen;
|
||||
int requireconversion;
|
||||
char value[16];
|
||||
|
||||
@ -900,24 +918,11 @@ extract(
|
||||
|
||||
requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype);
|
||||
|
||||
rank = segment->rank;
|
||||
ASSERT(xgetvar->cache != NULL);
|
||||
externtypesize = nctypesizeof(xgetvar->dsttype);
|
||||
interntypesize = nctypesizeof(xnode->etype);
|
||||
|
||||
if(rank == 0) {/* scalar */
|
||||
char* mem = (requireconversion?value:memory->next);
|
||||
ASSERT((segment != NULL));
|
||||
externtypesize = nctypesizeof(xgetvar->dsttype);
|
||||
ASSERT(externtypesize <= sizeof(value));
|
||||
/* Read the whole scalar directly into memory */
|
||||
ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,0,1);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
if(requireconversion) {
|
||||
/* convert the value to external type */
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
}
|
||||
memory->next += (externtypesize);
|
||||
|
||||
} else {/* rank > 0 */
|
||||
rank0 = nclistlength(xnode->array.dimset0);
|
||||
|
||||
#ifdef DEBUG2
|
||||
fprintf(stderr,"moveto: primitive: segment=%s",
|
||||
@ -926,92 +931,107 @@ fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable);
|
||||
fprintf(stderr,"\n");
|
||||
#endif
|
||||
|
||||
ASSERT(xgetvar->cache != NULL);
|
||||
if(xgetvar->cache->wholevariable) {
|
||||
odom = newdapodometer(segment->slices,0,rank);
|
||||
} else { /*!xgetvar->cache->wholevariable*/
|
||||
odom = newsimpledapodometer(segment,rank);
|
||||
}
|
||||
/* Optimize off the use of the odometer by checking the slicing
|
||||
to see if the whole variable, or some whole subslice
|
||||
is being extracted.
|
||||
However do not do this if the external type conversion is needed
|
||||
or if the whole slice point is rank-1 (normal case anyway).
|
||||
*/
|
||||
externtypesize = nctypesizeof(xgetvar->dsttype);
|
||||
interntypesize = nctypesizeof(xnode->etype);
|
||||
wholepoint = wholeslicepoint(odom);
|
||||
if(wholepoint == -1)
|
||||
odomsubsize = 1; /* no whole point */
|
||||
else
|
||||
odomsubsize = dapodometerspace(odom,wholepoint);
|
||||
internlen = (odomsubsize*interntypesize);
|
||||
if(requireconversion) {
|
||||
/* copy the data locally before conversion */
|
||||
localmemory = (char*)malloc(internlen);
|
||||
} else {
|
||||
localmemory = memory->next;
|
||||
if(rank0 == 0) {/* scalar */
|
||||
char* mem = (requireconversion?value:memory->next);
|
||||
ASSERT(externtypesize <= sizeof(value));
|
||||
/* Read the whole scalar directly into memory */
|
||||
ocstat = oc_data_readscalar(conn,currentcontent,externtypesize,mem);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
if(requireconversion) {
|
||||
/* convert the value to external type */
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
}
|
||||
memory->next += (externtypesize);
|
||||
} else if(xgetvar->cache->wholevariable) {/* && rank0 > 0 */
|
||||
/* There are multiple cases, assuming no conversion required.
|
||||
1) client is asking for whole variable
|
||||
=> start=0, count=totalsize, stride=1
|
||||
=> read whole thing at one shot
|
||||
2) client is asking for non-strided subset
|
||||
and edges are maximal
|
||||
=> start=x, count=y, stride=1
|
||||
=> read whole subset at one shot
|
||||
3) client is asking for strided subset or edges are not maximal
|
||||
=> start=x, count=y, stride=s
|
||||
=> we have to use odometer on leading prefix.
|
||||
If conversion required, then read one-by-one
|
||||
*/
|
||||
int safeindex = dcesafeindex(segment,0,rank0);
|
||||
assert(safeindex >= 0 && safeindex <= rank0);
|
||||
|
||||
#ifdef DEBUG2
|
||||
fprintf(stderr,"moveto: primitive: ");
|
||||
fprintf(stderr," wholepoint=%d",wholepoint);
|
||||
fprintf(stderr,"\n");
|
||||
#endif
|
||||
|
||||
if(wholepoint == 0) {/* whole variable */
|
||||
/* Read the whole n elements directly into memory.*/
|
||||
ocstat = oc_data_get(conn,currentcontent,localmemory,
|
||||
internlen,0,odomsubsize);
|
||||
if(!requireconversion && safeindex == 0) { /* can read whole thing */
|
||||
size_t internlen;
|
||||
count = dcesegmentsize(segment,0,rank0); /* how many to read */
|
||||
internlen = interntypesize*count;
|
||||
/* Read the whole variable directly into memory.*/
|
||||
ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next);
|
||||
/* bump memory pointer */
|
||||
memory->next += internlen;
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
if(requireconversion) {
|
||||
/* do conversion */
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,
|
||||
memory->next,localmemory,odomsubsize);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
}
|
||||
memory->next += (externtypesize*odomsubsize);
|
||||
} else if(wholepoint > 0) {/* whole subslice */
|
||||
odom->rank = wholepoint; /* truncate */
|
||||
while(dapodometermore(odom)) {
|
||||
size_t dimoffset = dapodometercount(odom) * odomsubsize;
|
||||
ocstat = oc_data_get(conn,currentcontent,localmemory,
|
||||
internlen,dimoffset,odomsubsize);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
if(requireconversion) {
|
||||
/* do conversion */
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,
|
||||
memory->next,localmemory,odomsubsize);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
}
|
||||
memory->next += (externtypesize*odomsubsize);
|
||||
dapodometerincr(odom);
|
||||
}
|
||||
} else { /* Oh well, use the odometer to walk to the
|
||||
appropriate fields*/
|
||||
while(dapodometermore(odom)) {
|
||||
char* mem = (requireconversion?value:memory->next);
|
||||
size_t dimoffset = dapodometercount(odom);
|
||||
ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,dimoffset,1);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
if(requireconversion) {
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
}
|
||||
memory->next += externtypesize;
|
||||
dapodometerincr(odom);
|
||||
}
|
||||
} else if(!requireconversion && safeindex > 0 && safeindex < rank0) {
|
||||
size_t internlen;
|
||||
/* We need to build an odometer for the unsafe prefix of the slices */
|
||||
odom = dapodom_fromsegment(segment,0,safeindex);
|
||||
count = dcesegmentsize(segment,safeindex,rank0); /* read in count chunks */
|
||||
internlen = interntypesize*count;
|
||||
while(dapodom_more(odom)) {
|
||||
ocstat = oc_data_readn(conn,currentcontent,odom->index,count,internlen,memory->next);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
memory->next += internlen;
|
||||
dapodom_next(odom);
|
||||
}
|
||||
dapodom_free(odom);
|
||||
} else {
|
||||
/* Cover following cases, all of which require reading
|
||||
values one-by-one:
|
||||
1. requireconversion
|
||||
2. !requireconversion but safeindex == rank0 =>no safe indices
|
||||
Note that in case 2, we will do a no-op conversion.
|
||||
*/
|
||||
odom = dapodom_fromsegment(segment,0,rank0);
|
||||
while(dapodom_more(odom)) {
|
||||
char value[16]; /* Big enough to hold any numeric value */
|
||||
ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
memory->next += (externtypesize);
|
||||
dapodom_next(odom);
|
||||
}
|
||||
dapodom_free(odom);
|
||||
}
|
||||
freedapodometer(odom);
|
||||
if(requireconversion) nullfree(localmemory);
|
||||
} else { /* !xgetvar->cache->wholevariable && rank0 > 0 */
|
||||
/* This is the case where the constraint was applied by the server,
|
||||
so we just read it in, possibly with conversion
|
||||
*/
|
||||
if(requireconversion) {
|
||||
/* read one-by-one */
|
||||
odom = dapodom_fromsegment(segment,0,rank0);
|
||||
while(dapodom_more(odom)) {
|
||||
char value[16]; /* Big enough to hold any numeric value */
|
||||
ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
memory->next += (externtypesize);
|
||||
dapodom_next(odom);
|
||||
}
|
||||
dapodom_free(odom);
|
||||
} else {/* Read straight to memory */
|
||||
size_t internlen;
|
||||
count = dcesegmentsize(segment,0,rank0); /* how many to read */
|
||||
internlen = interntypesize*count;
|
||||
ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
|
||||
}
|
||||
}
|
||||
done:
|
||||
return THROW(ncstat);
|
||||
}
|
||||
|
||||
|
||||
static NCerror
|
||||
slicestring(OCconnection conn, char* stringmem, DCEslice* slice, struct NCMEMORY* memory)
|
||||
slicestring(OClink conn, char* stringmem, DCEslice* slice, struct NCMEMORY* memory)
|
||||
{
|
||||
size_t stringlen;
|
||||
unsigned int i;
|
||||
@ -1059,50 +1079,50 @@ extractstring(
|
||||
Getvara* xgetvar,
|
||||
CDFnode* xnode,
|
||||
DCEsegment* segment,
|
||||
size_t dimindex, /*notused*/
|
||||
OClink conn,
|
||||
OCdata currentcontent,
|
||||
OCdatanode currentcontent,
|
||||
struct NCMEMORY* memory
|
||||
)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
int i;
|
||||
size_t rank;
|
||||
int caching = FLAGSET(nccomm->controls,NCF_CACHE);
|
||||
int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE);
|
||||
size_t rank0;
|
||||
NClist* strings = NULL;
|
||||
Dapodometer* odom = OCNULL;
|
||||
Dapodometer* odom = NULL;
|
||||
|
||||
rank = segment->rank;
|
||||
ASSERT(xnode->etype == NC_STRING || xnode->etype == NC_URL);
|
||||
|
||||
/* A number of optimizations are possible but none is currently used. */
|
||||
/* Compute rank minus string dimension */
|
||||
rank0 = nclistlength(xnode->array.dimset0);
|
||||
|
||||
/* Use the odometer to walk to the appropriate fields*/
|
||||
if(rank == 1) {
|
||||
odom = newdapodometer1(1); /* scalar case */
|
||||
} else if(caching || unconstrainable) {
|
||||
odom = newdapodometer(segment->slices,0,rank-1);
|
||||
} else { /*Since vara was projected out, build a simple odometer*/
|
||||
odom = newsimpledapodometer(segment,rank-1);
|
||||
}
|
||||
|
||||
/* step thru the odometer obtaining each string and storing it in an OClist */
|
||||
/* keep whole extracted strings stored in an NClist */
|
||||
strings = nclistnew();
|
||||
nclistsetalloc(strings,dapodometerspace(odom,0)); /* preallocate */
|
||||
while(dapodometermore(odom)) {
|
||||
|
||||
if(rank0 == 0) {/*=> scalar*/
|
||||
char* value = NULL;
|
||||
size_t dimoffset = dapodometercount(odom);
|
||||
ocstat = oc_data_get(conn,currentcontent,&value,sizeof(value),dimoffset,1);
|
||||
ocstat = oc_data_readscalar(conn,currentcontent,sizeof(value),&value);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
nclistpush(strings,(ncelem)value);
|
||||
dapodometerincr(odom);
|
||||
} else {
|
||||
/* Use the odometer to walk to the appropriate fields*/
|
||||
odom = dapodom_fromsegment(segment,0,rank0);
|
||||
while(dapodom_more(odom)) {
|
||||
char* value = NULL;
|
||||
ocstat = oc_data_readn(conn,currentcontent,odom->index,1,sizeof(value),&value);
|
||||
if(ocstat != OC_NOERR) goto done;
|
||||
nclistpush(strings,(ncelem)value);
|
||||
dapodom_next(odom);
|
||||
}
|
||||
dapodom_free(odom);
|
||||
}
|
||||
freedapodometer(odom);
|
||||
/* Get each string in turn, slice it and store in user
|
||||
supplied memory */
|
||||
/* Get each string in turn, slice it by applying the string dimm
|
||||
and store in user supplied memory
|
||||
*/
|
||||
for(i=0;i<nclistlength(strings);i++) {
|
||||
char* s = (char*)nclistget(strings,i);
|
||||
slicestring(conn,s,&segment->slices[rank-1],memory);
|
||||
slicestring(conn,s,&segment->slices[rank0],memory);
|
||||
free(s);
|
||||
}
|
||||
nclistfree(strings);
|
||||
|
@ -32,7 +32,7 @@
|
||||
#define NC_Structure 54
|
||||
#define NC_Grid 55
|
||||
#define NC_Dimension 56
|
||||
#define NC_Primitive 57
|
||||
#define NC_Atomic 57
|
||||
|
||||
#undef OCCOMPILEBYDEFAULT
|
||||
|
||||
@ -93,14 +93,14 @@ struct NCTMODEL {
|
||||
|
||||
/* Detail information about each cache item */
|
||||
typedef struct NCcachenode {
|
||||
int wholevariable; /* does this node only have wholevariables? */
|
||||
int wholevariable; /* does this cache node only have wholevariables? */
|
||||
int prefetch; /* is this the prefetch cache entry? */
|
||||
size_t xdrsize;
|
||||
off_t xdrsize;
|
||||
DCEconstraint* constraint; /* as used to create this node */
|
||||
NClist* vars; /* vars potentially covered by this cache node */
|
||||
struct CDFnode* datadds;
|
||||
OCobject ocroot;
|
||||
OCdata content;
|
||||
OCddsnode ocroot;
|
||||
OCdatanode content;
|
||||
} NCcachenode;
|
||||
|
||||
/* All cache info */
|
||||
@ -115,11 +115,11 @@ typedef struct NCcache {
|
||||
/**************************************************/
|
||||
/* The DAP packet info from OC */
|
||||
typedef struct NCOC {
|
||||
OCconnection conn;
|
||||
OClink conn;
|
||||
char* rawurltext; /* as given to nc3d_open */
|
||||
char* urltext; /* as modified by nc3d_open */
|
||||
NC_URI* url; /* parse of rawuritext */
|
||||
OCobject ocdasroot;
|
||||
OCdasnode ocdasroot;
|
||||
DCEconstraint* dapconstraint; /* from url */
|
||||
int inmemory; /* store fetched data in memory? */
|
||||
} NCOC;
|
||||
@ -132,6 +132,7 @@ typedef struct NCCDF {
|
||||
NClist* seqnodes; /* sequence nodes; */
|
||||
NClist* gridnodes; /* grid nodes */
|
||||
NClist* dimnodes; /* (base) dimension nodes */
|
||||
NClist* projectedvars; /* vars appearing in nc_open url projections */
|
||||
unsigned int defaultstringlength;
|
||||
unsigned int defaultsequencelimit; /* global sequence limit;0=>no limit */
|
||||
struct NCcache* cache;
|
||||
@ -161,7 +162,7 @@ typedef struct NCDAPCOMMON {
|
||||
|
||||
/* Each root CDFnode contains info about the whole tree */
|
||||
typedef struct CDFtree {
|
||||
OCobject ocroot;
|
||||
OCddsnode ocroot;
|
||||
OCdxd occlass;
|
||||
NClist* nodes; /* all nodes in tree*/
|
||||
struct CDFnode* root; /* cross link */
|
||||
@ -235,7 +236,7 @@ typedef struct CDFnode {
|
||||
char* ocname; /* oc base name */
|
||||
char* ncbasename; /* generally cdflegalname(ocname) */
|
||||
char* ncfullname; /* complete path name from root to this node*/
|
||||
OCobject ocnode; /* oc mirror node*/
|
||||
OCddsnode ocnode; /* oc mirror node*/
|
||||
struct CDFnode* group; /* null => in root group */
|
||||
struct CDFnode* container; /* e.g. struct or sequence, but not group */
|
||||
struct CDFnode* root;
|
||||
@ -275,26 +276,26 @@ typedef struct CDFnode {
|
||||
/* Shared procedures */
|
||||
|
||||
/* From ncdap3.c*/
|
||||
extern NCerror freeNCDAPCOMMON(struct NCDAPCOMMON*);
|
||||
extern NCerror freeNCDAPCOMMON(NCDAPCOMMON*);
|
||||
extern NCerror fetchtemplatemetadata3(NCDAPCOMMON*);
|
||||
|
||||
/* From error.c*/
|
||||
extern NCerror ocerrtoncerr(OCerror);
|
||||
|
||||
/* From: common34.c */
|
||||
extern NCerror fixgrid34(struct NCDAPCOMMON* drno, CDFnode* grid);
|
||||
extern NCerror computecdfinfo34(struct NCDAPCOMMON*, NClist*);
|
||||
extern NCerror fixgrid34(NCDAPCOMMON* drno, CDFnode* grid);
|
||||
extern NCerror computecdfinfo34(NCDAPCOMMON*, NClist*);
|
||||
extern char* cdfname34(char* basename);
|
||||
extern NCerror augmentddstree34(struct NCDAPCOMMON*, NClist*);
|
||||
extern NCerror computecdfdimnames34(struct NCDAPCOMMON*);
|
||||
extern NCerror buildcdftree34(struct NCDAPCOMMON*, OCobject, OCdxd, CDFnode**);
|
||||
extern CDFnode* makecdfnode34(struct NCDAPCOMMON*, char* nm, OCtype,
|
||||
/*optional*/ OCobject ocnode, CDFnode* container);
|
||||
extern NCerror augmentddstree34(NCDAPCOMMON*, NClist*);
|
||||
extern NCerror computecdfdimnames34(NCDAPCOMMON*);
|
||||
extern NCerror buildcdftree34(NCDAPCOMMON*, OCddsnode, OCdxd, CDFnode**);
|
||||
extern CDFnode* makecdfnode34(NCDAPCOMMON*, char* nm, OCtype,
|
||||
/*optional*/ OCddsnode ocnode, CDFnode* container);
|
||||
extern void freecdfroot34(CDFnode*);
|
||||
|
||||
extern NCerror findnodedds34(struct NCDAPCOMMON* drno, CDFnode* ddssrc);
|
||||
extern NCerror makegetvar34(struct NCDAPCOMMON*, struct CDFnode*, void*, nc_type, struct Getvara**);
|
||||
extern NCerror applyclientparams34(struct NCDAPCOMMON* drno);
|
||||
extern NCerror findnodedds34(NCDAPCOMMON* drno, CDFnode* ddssrc);
|
||||
extern NCerror makegetvar34(NCDAPCOMMON*, struct CDFnode*, void*, nc_type, struct Getvara**);
|
||||
extern NCerror applyclientparams34(NCDAPCOMMON* drno);
|
||||
extern NCerror attach34(CDFnode* xroot, CDFnode* ddstarget);
|
||||
extern NCerror attachall34(CDFnode* xroot, CDFnode* ddsroot);
|
||||
extern NCerror attachsubset34(CDFnode*, CDFnode*);
|
||||
@ -310,7 +311,7 @@ extern NClist* getalldims34(NCDAPCOMMON* nccomm, int visibleonly);
|
||||
|
||||
/* From cdf3.c */
|
||||
extern NCerror dimimprint3(NCDAPCOMMON*);
|
||||
extern NCerror definedimsets3(struct NCDAPCOMMON*);
|
||||
extern NCerror definedimsets3(NCDAPCOMMON*);
|
||||
|
||||
/* From cache.c */
|
||||
extern int iscached(NCDAPCOMMON*, CDFnode* target, NCcachenode** cachenodep);
|
||||
|
@ -29,9 +29,11 @@ static NCerror buildattribute3a(NCDAPCOMMON*, NCattribute*, nc_type, int);
|
||||
|
||||
static char* getdefinename(CDFnode* node);
|
||||
|
||||
extern CDFnode* v4node;
|
||||
int nc3dinitialized = 0;
|
||||
|
||||
size_t dap_one[NC_MAX_VAR_DIMS];
|
||||
size_t dap_zero[NC_MAX_VAR_DIMS];
|
||||
|
||||
/**************************************************/
|
||||
/* Add an extra function whose sole purpose is to allow
|
||||
configure(.ac) to test for the presence of thiscode.
|
||||
@ -44,8 +46,22 @@ int nc__opendap(void) {return 0;}
|
||||
int
|
||||
nc3dinitialize(void)
|
||||
{
|
||||
int i;
|
||||
compute_nccalignments();
|
||||
for(i=0;i<NC_MAX_VAR_DIMS;i++) {
|
||||
dap_one[i] = 1;
|
||||
dap_zero[i] = 0;
|
||||
}
|
||||
nc3dinitialized = 1;
|
||||
#if 0
|
||||
/* This is causing a hang */
|
||||
#ifdef DEBUG
|
||||
/* force logging to go to stderr */
|
||||
nclogclose();
|
||||
nclogopen(NULL);
|
||||
ncsetlogging(1); /* turn it on */
|
||||
#endif
|
||||
#endif
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
@ -117,6 +133,16 @@ NCD3_open(const char * path, int mode,
|
||||
if(!constrainable34(dapcomm->oc.url))
|
||||
SETFLAG(dapcomm->controls,NCF_UNCONSTRAINABLE);
|
||||
|
||||
/* fail if we are unconstrainable but have constraints */
|
||||
if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
|
||||
if(dapcomm->oc.url->constraint != NULL) {
|
||||
nclog(NCLOGWARN,"Attempt to constrain an unconstrainable data source: %s",
|
||||
dapcomm->oc.url->constraint);
|
||||
ncstat = THROW(NC_EDAPCONSTRAINT);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use libsrc code for storing metadata */
|
||||
|
||||
snprintf(tmpname,sizeof(tmpname),"%d",drno->int_ncid);
|
||||
@ -133,23 +159,17 @@ NCD3_open(const char * path, int mode,
|
||||
dapcomm->oc.dapconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
|
||||
dapcomm->oc.dapconstraint->projections = nclistnew();
|
||||
dapcomm->oc.dapconstraint->selections = nclistnew();
|
||||
|
||||
if(dapcomm->oc.url != NULL) {
|
||||
/* Parse constraints to make sure they are syntactically correct */
|
||||
ncstat = parsedapconstraints(dapcomm,dapcomm->oc.url->constraint,dapcomm->oc.dapconstraint);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
} else
|
||||
dapcomm->oc.dapconstraint = NULL;
|
||||
|
||||
/* Parse constraints to make sure they are syntactically correct */
|
||||
ncstat = parsedapconstraints(dapcomm,dapcomm->oc.url->constraint,dapcomm->oc.dapconstraint);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
|
||||
|
||||
/* Complain if we are unconstrainable but have constraints */
|
||||
if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
|
||||
if(dapcomm->oc.url->constraint != NULL
|
||||
&& strlen(dapcomm->oc.url->constraint) > 0) {
|
||||
nclog(NCLOGWARN,"Attempt to constrain an unconstrainable data source: %s",
|
||||
dapcomm->oc.url->constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct a url for oc minus any parameters */
|
||||
/* Construct a url for oc minus any constraint */
|
||||
dapcomm->oc.urltext = nc_uribuild(dapcomm->oc.url,NULL,NULL,
|
||||
(NC_URIALL ^ NC_URICONSTRAINTS));
|
||||
(NC_URIALL ^ NC_URICONSTRAINTS));
|
||||
|
||||
/* Pass to OC */
|
||||
ocstat = oc_open(dapcomm->oc.urltext,&dapcomm->oc.conn);
|
||||
@ -171,7 +191,7 @@ NCD3_open(const char * path, int mode,
|
||||
oc_logopen(value);
|
||||
}
|
||||
|
||||
/* fetch and build the (almost) unconstrained DDS for use as
|
||||
/* fetch and build the unconstrained DDS for use as
|
||||
template */
|
||||
ncstat = fetchtemplatemetadata3(dapcomm);
|
||||
if(ncstat != NC_NOERR) goto done;
|
||||
@ -262,6 +282,10 @@ fprintf(stderr,"constrained dds: %s\n",dumptree(dapcomm->cdf.ddsroot));
|
||||
ncstat = qualifyconstraints3(dapcomm->oc.dapconstraint);
|
||||
if(ncstat != NC_NOERR) goto done;
|
||||
|
||||
/* Accumulate set of variables in the constraint's projections */
|
||||
ncstat = computeprojectedvars(dapcomm,dapcomm->oc.dapconstraint);
|
||||
if(ncstat) {THROWCHK(ncstat); goto done;}
|
||||
|
||||
/* using the modified constraint, rebuild the constraint string */
|
||||
if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
|
||||
/* ignore all constraints */
|
||||
@ -573,7 +597,7 @@ buildglobalattrs3(NCDAPCOMMON* dapcomm, CDFnode* root)
|
||||
if(paramcheck34(dapcomm,"show","dds")) {
|
||||
txt = NULL;
|
||||
if(dapcomm->cdf.ddsroot != NULL)
|
||||
txt = oc_inq_text(dapcomm->oc.conn,dapcomm->cdf.ddsroot->ocnode);
|
||||
txt = oc_tree_text(dapcomm->oc.conn,dapcomm->cdf.ddsroot->ocnode);
|
||||
if(txt != NULL) {
|
||||
/* replace newlines with spaces*/
|
||||
nltxt = nulldup(txt);
|
||||
@ -584,8 +608,8 @@ buildglobalattrs3(NCDAPCOMMON* dapcomm, CDFnode* root)
|
||||
}
|
||||
if(paramcheck34(dapcomm,"show","das")) {
|
||||
txt = NULL;
|
||||
if(dapcomm->oc.ocdasroot != OCNULL)
|
||||
txt = oc_inq_text(dapcomm->oc.conn,dapcomm->oc.ocdasroot);
|
||||
if(dapcomm->oc.ocdasroot != NULL)
|
||||
txt = oc_tree_text(dapcomm->oc.conn,dapcomm->oc.ocdasroot);
|
||||
if(txt != NULL) {
|
||||
nltxt = nulldup(txt);
|
||||
for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}};
|
||||
@ -664,7 +688,7 @@ getdefinename(CDFnode* node)
|
||||
NClist* path = NULL;
|
||||
|
||||
switch (node->nctype) {
|
||||
case NC_Primitive:
|
||||
case NC_Atomic:
|
||||
/* The define name is same as the fullname with elided nodes */
|
||||
path = nclistnew();
|
||||
collectnodepath3(node,path,!WITHDATASET);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "nchashmap.h"
|
||||
#include "nclog.h"
|
||||
#include "nc_uri.h"
|
||||
|
||||
#include "fbits.h"
|
||||
#include "dceconstraints.h"
|
||||
|
||||
@ -107,7 +108,7 @@ extern void dereference3(NCconstraint* constraint);
|
||||
extern NCerror rereference3(NCconstraint*, NClist*);
|
||||
*/
|
||||
|
||||
extern NCerror buildvaraprojection3(struct Getvara*,
|
||||
extern NCerror buildvaraprojection3(CDFnode*,
|
||||
const size_t* startp, const size_t* countp, const ptrdiff_t* stridep,
|
||||
struct DCEprojection** projectionlist);
|
||||
|
||||
@ -121,6 +122,9 @@ extern NCerror nc3d_getvarx(int ncid, int varid,
|
||||
/**************************************************/
|
||||
|
||||
/* From: ncdap3.c*/
|
||||
extern size_t dap_one[NC_MAX_VAR_DIMS];
|
||||
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);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*********************************************************************
|
||||
/********************************************************************* \
|
||||
* Copyright 1993, UCAR/Unidata
|
||||
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
||||
*********************************************************************/
|
||||
@ -79,7 +79,7 @@ addstringdims(NCDAPCOMMON* dapcomm)
|
||||
/* Start by creating the global string dimension */
|
||||
snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
|
||||
(unsigned long)dapcomm->cdf.defaultstringlength);
|
||||
globalsdim = makecdfnode34(dapcomm, dimname, OC_Dimension, OCNULL,
|
||||
globalsdim = makecdfnode34(dapcomm, dimname, OC_Dimension, NULL,
|
||||
dapcomm->cdf.ddsroot);
|
||||
nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(ncelem)globalsdim);
|
||||
DIMFLAGSET(globalsdim,CDFDIMSTRING);
|
||||
@ -113,7 +113,7 @@ addstringdims(NCDAPCOMMON* dapcomm)
|
||||
else
|
||||
snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
|
||||
(unsigned long)dimsize);
|
||||
sdim = makecdfnode34(dapcomm, dimname, OC_Dimension, OCNULL,
|
||||
sdim = makecdfnode34(dapcomm, dimname, OC_Dimension, NULL,
|
||||
dapcomm->cdf.ddsroot);
|
||||
if(sdim == NULL) return THROW(NC_ENOMEM);
|
||||
nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(ncelem)sdim);
|
||||
@ -211,9 +211,9 @@ getseqdimsize(NCDAPCOMMON* dapcomm, CDFnode* seq, size_t* sizep)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCconnection conn = dapcomm->oc.conn;
|
||||
OCdata rootcontent = OCNULL;
|
||||
OCobject ocroot;
|
||||
OClink conn = dapcomm->oc.conn;
|
||||
OCdatanode rootcontent = NULL;
|
||||
OCddsnode ocroot;
|
||||
CDFnode* dxdroot;
|
||||
CDFnode* xseq;
|
||||
NCbytes* seqcountconstraints = ncbytesnew();
|
||||
@ -280,7 +280,7 @@ makeseqdim(NCDAPCOMMON* dapcomm, CDFnode* seq, size_t count, CDFnode** sqdimp)
|
||||
CDFtree* tree = root->tree;
|
||||
|
||||
/* build the dimension with given size; keep the dimension anonymous */
|
||||
sqdim = makecdfnode34(dapcomm,seq->ocname,OC_Dimension,OCNULL,root);
|
||||
sqdim = makecdfnode34(dapcomm,seq->ocname,OC_Dimension,NULL,root);
|
||||
if(sqdim == NULL) return THROW(NC_ENOMEM);
|
||||
nclistpush(tree->nodes,(ncelem)sqdim);
|
||||
/* Assign a name to the sequence node */
|
||||
@ -302,12 +302,10 @@ countsequence(NCDAPCOMMON* dapcomm, CDFnode* xseq, size_t* sizep)
|
||||
int index;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCconnection conn = dapcomm->oc.conn;
|
||||
OClink conn = dapcomm->oc.conn;
|
||||
size_t recordcount;
|
||||
CDFnode* xroot;
|
||||
CDFnode* current;
|
||||
OCdata datacontainer = OCNULL;
|
||||
OCmode mode;
|
||||
OCdatanode data = NULL;
|
||||
|
||||
ASSERT((xseq->nctype == NC_Sequence));
|
||||
|
||||
@ -315,50 +313,58 @@ countsequence(NCDAPCOMMON* dapcomm, CDFnode* xseq, size_t* sizep)
|
||||
collectnodepath3(xseq,path,WITHDATASET);
|
||||
|
||||
/* Get tree root */
|
||||
ASSERT(xseq->root == (CDFnode*)nclistget(path,0));
|
||||
xroot = xseq->root;
|
||||
datacontainer = oc_data_new(conn);
|
||||
ocstat = oc_data_root(conn,xroot->tree->ocroot,datacontainer);
|
||||
if(ocstat) goto fail;
|
||||
ocstat = oc_data_getroot(conn,xroot->tree->ocroot,&data);
|
||||
if(ocstat) goto done;
|
||||
|
||||
/* walk to the sequence object; control the movement to the next node
|
||||
based on mode */
|
||||
current = (CDFnode*)nclistget(path,0);
|
||||
for(i=0;;) {
|
||||
OCdata child = OCNULL;
|
||||
CDFnode* next = NULL;
|
||||
ocstat = oc_data_mode(conn,datacontainer,&mode);
|
||||
if(ocstat != OC_NOERR) goto fail;
|
||||
switch (mode) {
|
||||
case OCFIELDMODE:
|
||||
i++;
|
||||
next = (CDFnode*)nclistget(path,i);
|
||||
/* Basically we use the path to walk the data instances to reach
|
||||
the sequence instance
|
||||
*/
|
||||
for(i=0;i<nclistlength(path);i++) {
|
||||
CDFnode* current = (CDFnode*)nclistget(path,i);
|
||||
OCdatanode nextdata = NULL;
|
||||
CDFnode* next = NULL;
|
||||
|
||||
/* invariant: current = ith node in path; data = corresponding
|
||||
datanode
|
||||
*/
|
||||
|
||||
/* get next node in next and next instance in nextdata */
|
||||
if(current->nctype == NC_Structure
|
||||
|| current->nctype == NC_Dataset) {
|
||||
if(nclistlength(current->array.dimset0) > 0) {
|
||||
/* Cannot handle this case */
|
||||
ncstat = THROW(NC_EDDS);
|
||||
goto done;
|
||||
}
|
||||
/* get next node in path; structure/dataset => exists */
|
||||
next = (CDFnode*)nclistget(path,i+1);
|
||||
index = fieldindex(current,next);
|
||||
break;
|
||||
case OCARRAYMODE:
|
||||
index = 0;
|
||||
break;
|
||||
case OCSEQUENCEMODE:
|
||||
goto exitloop;
|
||||
default:
|
||||
/* Move to appropriate field */
|
||||
ocstat = oc_data_ithfield(conn,data,index,&nextdata);
|
||||
if(ocstat) goto done;
|
||||
oc_data_free(conn,data);
|
||||
data = nextdata; /* set up for next loop iteration */
|
||||
} else if(current->nctype == NC_Sequence) {
|
||||
/* Check for nested Sequences */
|
||||
if(current != xseq) {
|
||||
/* Cannot handle this case */
|
||||
ncstat = THROW(NC_EDDS);
|
||||
goto done;
|
||||
}
|
||||
/* Get the record count */
|
||||
ocstat = oc_data_recordcount(conn,data,&recordcount);
|
||||
if(sizep) *sizep = recordcount;
|
||||
oc_data_free(conn,data); /* reclaim */
|
||||
break; /* leave the loop */
|
||||
} else {
|
||||
PANIC("unexpected mode");
|
||||
return NC_EINVAL;
|
||||
}
|
||||
child = oc_data_new(conn);
|
||||
ocstat = oc_data_ith(conn,datacontainer,index,child);
|
||||
if(ocstat) goto fail;
|
||||
/* move to the next node only if it is defined */
|
||||
if(next != NULL)
|
||||
current = next;
|
||||
oc_data_free(conn,datacontainer);
|
||||
datacontainer = child;
|
||||
}
|
||||
exitloop:
|
||||
ASSERT(current == xseq && mode == OCSEQUENCEMODE);
|
||||
oc_data_count(conn,datacontainer,&recordcount);
|
||||
if(sizep) *sizep = recordcount;
|
||||
|
||||
fail:
|
||||
oc_data_free(conn,datacontainer);
|
||||
done:
|
||||
nclistfree(path);
|
||||
if(ocstat) ncstat = ocerrtoncerr(ocstat);
|
||||
return THROW(ncstat);
|
||||
@ -493,7 +499,7 @@ prefer(CDFnode* candidate, CDFnode* newchoice)
|
||||
newisscalar = (nclistlength(newchoice->array.dimset0) == 0);
|
||||
canisscalar = (nclistlength(candidate->array.dimset0) == 0);
|
||||
|
||||
ASSERT(candidate->nctype == NC_Primitive && newchoice->nctype == NC_Primitive);
|
||||
ASSERT(candidate->nctype == NC_Atomic && newchoice->nctype == NC_Atomic);
|
||||
|
||||
/* choose non-string over string */
|
||||
if(canisstring && !newisstring)
|
||||
@ -522,13 +528,12 @@ computeseqcountconstraints3r(NCDAPCOMMON* dapcomm, CDFnode* node, CDFnode** cand
|
||||
candidate = NULL;
|
||||
compound = NULL;
|
||||
|
||||
for(i=0;i<nclistlength(node->subnodes);i++){
|
||||
for(i=0;i<nclistlength(node->subnodes);i++) {
|
||||
CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
|
||||
if(subnode->nctype == NC_Structure || subnode->nctype == NC_Grid)
|
||||
compound = subnode; /* save for later recursion */
|
||||
else if(subnode->nctype == NC_Primitive) {
|
||||
else if(subnode->nctype == NC_Atomic)
|
||||
candidate = prefer(candidate,subnode);
|
||||
}
|
||||
}
|
||||
if(candidate == NULL && compound == NULL) {
|
||||
PANIC("cannot find candidate for seqcountconstraints for a sequence");
|
||||
@ -597,7 +602,7 @@ fetchtemplatemetadata3(NCDAPCOMMON* dapcomm)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCobject ocroot = OCNULL;
|
||||
OCddsnode ocroot = NULL;
|
||||
CDFnode* ddsroot = NULL;
|
||||
char* ce = NULL;
|
||||
|
||||
@ -635,7 +640,7 @@ fetchtemplatemetadata3(NCDAPCOMMON* dapcomm)
|
||||
if(ocstat != OC_NOERR) {
|
||||
/* Ignore but complain */
|
||||
nclog(NCLOGWARN,"Could not read DAS; ignored");
|
||||
dapcomm->oc.ocdasroot = OCNULL;
|
||||
dapcomm->oc.ocdasroot = NULL;
|
||||
ocstat = OC_NOERR;
|
||||
}
|
||||
|
||||
@ -655,7 +660,7 @@ fetchconstrainedmetadata3(NCDAPCOMMON* dapcomm)
|
||||
{
|
||||
NCerror ncstat = NC_NOERR;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCobject ocroot;
|
||||
OCddsnode ocroot;
|
||||
CDFnode* ddsroot; /* constrained */
|
||||
char* ce = NULL;
|
||||
|
||||
@ -663,7 +668,6 @@ fetchconstrainedmetadata3(NCDAPCOMMON* dapcomm)
|
||||
ce = NULL;
|
||||
else
|
||||
ce = buildconstraintstring3(dapcomm->oc.dapconstraint);
|
||||
|
||||
{
|
||||
ocstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDDS,&ocroot);
|
||||
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
|
||||
@ -671,27 +675,30 @@ fetchconstrainedmetadata3(NCDAPCOMMON* dapcomm)
|
||||
/* Construct our parallel dds tree; including attributes*/
|
||||
ncstat = buildcdftree34(dapcomm,ocroot,OCDDS,&ddsroot);
|
||||
if(ncstat) goto fail;
|
||||
ocroot = NULL; /* avoid duplicate reclaim */
|
||||
|
||||
dapcomm->cdf.ddsroot = ddsroot;
|
||||
ddsroot = NULL; /* to avoid double reclamation */
|
||||
|
||||
if(!FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
|
||||
/* fix DAP server problem by adding back any missing grid structure nodes */
|
||||
ncstat = regrid3(ddsroot,dapcomm->cdf.fullddsroot,dapcomm->oc.dapconstraint->projections);
|
||||
ncstat = regrid3(dapcomm->cdf.ddsroot,dapcomm->cdf.fullddsroot,dapcomm->oc.dapconstraint->projections);
|
||||
if(ncstat) goto fail;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"constrained:\n%s",dumptree(ddsroot));
|
||||
fprintf(stderr,"constrained:\n%s",dumptree(dapcomm->cdf.ddsroot));
|
||||
#endif
|
||||
|
||||
/* Combine DDS and DAS */
|
||||
if(dapcomm->oc.ocdasroot != NULL) {
|
||||
ncstat = dapmerge3(dapcomm,ddsroot,dapcomm->oc.ocdasroot);
|
||||
ncstat = dapmerge3(dapcomm,dapcomm->cdf.ddsroot->ocnode,
|
||||
dapcomm->oc.ocdasroot);
|
||||
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
|
||||
}
|
||||
|
||||
/* map the constrained DDS to the unconstrained DDS */
|
||||
ncstat = mapnodes3(ddsroot,dapcomm->cdf.fullddsroot);
|
||||
ncstat = mapnodes3(dapcomm->cdf.ddsroot,dapcomm->cdf.fullddsroot);
|
||||
if(ncstat) goto fail;
|
||||
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ if test 0 = 1 ; then
|
||||
echo "*** SUCCEED: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test "x${isxfail}" = "x1" ; then
|
||||
echo "*** XFAIL: ${x}"
|
||||
echo "*** XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "*** FAIL: ${x}"
|
||||
|
@ -185,7 +185,7 @@ nc_strerror(int ncerr1)
|
||||
case NC_EDAPURL:
|
||||
return "NetCDF: Malformed URL";
|
||||
case NC_EDAPCONSTRAINT:
|
||||
return "NetCDF: Malformed Constraint";
|
||||
return "NetCDF: Malformed or unexpected Constraint";
|
||||
case NC_ETRANSLATION:
|
||||
return "NetCDF: Untranslatable construct";
|
||||
case NC_EHDFERR:
|
||||
|
@ -1,187 +0,0 @@
|
||||
/*! \file
|
||||
Functions for netCDF-4 features.
|
||||
|
||||
Copyright 2010 University Corporation for Atmospheric
|
||||
Research/Unidata. See \ref COPYRIGHT file for more info. */
|
||||
|
||||
#include "ncdispatch.h"
|
||||
|
||||
/** \defgroup user_types User-Defined Types
|
||||
|
||||
User defined types allow for more complex data structures.
|
||||
|
||||
NetCDF-4 has added support for four different user defined data
|
||||
types. User defined type may only be used in files created with the
|
||||
::NC_NETCDF4 and without ::NC_CLASSIC_MODEL.
|
||||
- compound type: like a C struct, a compound type is a collection of
|
||||
types, including other user defined types, in one package.
|
||||
- variable length array type: used to store ragged arrays.
|
||||
- opaque type: This type has only a size per element, and no other
|
||||
type information.
|
||||
- enum type: Like an enumeration in C, this type lets you assign text
|
||||
values to integer values, and store the integer values.
|
||||
|
||||
Users may construct user defined type with the various nc_def_*
|
||||
functions described in this section. They may learn about user defined
|
||||
types by using the nc_inq_ functions defined in this section.
|
||||
|
||||
Once types are constructed, define variables of the new type with
|
||||
nc_def_var (see nc_def_var). Write to them with nc_put_var1,
|
||||
nc_put_var, nc_put_vara, or nc_put_vars. Read data of user-defined
|
||||
type with nc_get_var1, nc_get_var, nc_get_vara, or nc_get_vars (see
|
||||
\ref variables).
|
||||
|
||||
Create attributes of the new type with nc_put_att (see nc_put_att_
|
||||
type). Read attributes of the new type with nc_get_att (see
|
||||
\ref attributes).
|
||||
*/
|
||||
/** \{ */
|
||||
|
||||
/** \} */
|
||||
|
||||
/** \defgroup groups Groups
|
||||
|
||||
NetCDF-4 added support for hierarchical groups within netCDF datasets.
|
||||
|
||||
Groups are identified with a ncid, which identifies both the open
|
||||
file, and the group within that file. When a file is opened with
|
||||
nc_open or nc_create, the ncid for the root group of that file is
|
||||
provided. Using that as a starting point, users can add new groups, or
|
||||
list and navigate existing groups.
|
||||
|
||||
All netCDF calls take a ncid which determines where the call will take
|
||||
its action. For example, the nc_def_var function takes a ncid as its
|
||||
first parameter. It will create a variable in whichever group its ncid
|
||||
refers to. Use the root ncid provided by nc_create or nc_open to
|
||||
create a variable in the root group. Or use nc_def_grp to create a
|
||||
group and use its ncid to define a variable in the new group.
|
||||
|
||||
Variable are only visible in the group in which they are defined. The
|
||||
same applies to attributes. “Global” attributes are associated with
|
||||
the group whose ncid is used.
|
||||
|
||||
Dimensions are visible in their groups, and all child groups.
|
||||
|
||||
Group operations are only permitted on netCDF-4 files - that is, files
|
||||
created with the HDF5 flag in nc_create(). Groups are not compatible
|
||||
with the netCDF classic data model, so files created with the
|
||||
::NC_CLASSIC_MODEL file cannot contain groups (except the root group).
|
||||
|
||||
*/
|
||||
/** \{ */
|
||||
int
|
||||
nc_inq_ncid(int ncid, const char *name, int *grp_ncid)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_ncid(ncid,name,grp_ncid);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grps(int ncid, int *numgrps, int *ncids)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_grps(ncid,numgrps,ncids);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grpname(int ncid, char *name)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_grpname(ncid,name);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grpname_full(int ncid, size_t *lenp, char *full_name)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_grpname_full(ncid,lenp,full_name);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grpname_len(int ncid, size_t *lenp)
|
||||
{
|
||||
int stat = nc_inq_grpname_full(ncid,lenp,NULL);
|
||||
return stat;
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grp_parent(int ncid, int *parent_ncid)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_grp_parent(ncid,parent_ncid);
|
||||
}
|
||||
|
||||
/* This has same semantics as nc_inq_ncid */
|
||||
int
|
||||
nc_inq_grp_ncid(int ncid, const char *grp_name, int *grp_ncid)
|
||||
{
|
||||
return nc_inq_ncid(ncid,grp_name,grp_ncid);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_grp_full_ncid(ncid,full_name,grp_ncid);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_varids(int ncid, int *nvars, int *varids)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_varids(ncid,nvars,varids);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_dimids(int ncid, int *ndims, int *dimids, int include_parents)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_dimids(ncid,ndims,dimids,include_parents);
|
||||
}
|
||||
|
||||
int
|
||||
nc_inq_typeids(int ncid, int *ntypes, int *typeids)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->inq_typeids(ncid,ntypes,typeids);
|
||||
}
|
||||
|
||||
int
|
||||
nc_def_grp(int parent_ncid, const char *name, int *new_ncid)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(parent_ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->def_grp(parent_ncid,name,new_ncid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
nc_show_metadata(int ncid)
|
||||
{
|
||||
NC* ncp;
|
||||
int stat = NC_check_id(ncid,&ncp);
|
||||
if(stat != NC_NOERR) return stat;
|
||||
return ncp->dispatch->show_metadata(ncid);
|
||||
}
|
||||
|
||||
/** \} */
|
@ -114,7 +114,7 @@ ncbytesappend(NCbytes* bb, char elem)
|
||||
|
||||
/* This assumes s is a null terminated string*/
|
||||
int
|
||||
ncbytescat(NCbytes* bb, char* s)
|
||||
ncbytescat(NCbytes* bb, const char* s)
|
||||
{
|
||||
ncbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
|
||||
/* back up over the trailing null*/
|
||||
|
@ -39,7 +39,7 @@ ${top_builddir}/libsrc/libnetcdf3.la
|
||||
if USE_DAP
|
||||
AM_CPPFLAGS += -I${top_srcdir}/libdap2 -I${top_srcdir}/oc
|
||||
libnetcdf_la_LIBADD += ${top_builddir}/libdap2/libdap2.la
|
||||
libnetcdf_la_LIBADD += ${top_builddir}/oc/liboc.la
|
||||
libnetcdf_la_LIBADD += ${top_builddir}/oc2/liboc.la
|
||||
endif # USE_DAP
|
||||
|
||||
# NetCDF-4 ...
|
||||
|
@ -3142,7 +3142,6 @@ NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp)
|
||||
if (unlimdimidp)
|
||||
{
|
||||
/* Default, no unlimited dimension */
|
||||
int found = 0;
|
||||
*unlimdimidp = -1;
|
||||
|
||||
/* If there's more than one unlimited dim, which was not possible
|
||||
|
@ -834,7 +834,6 @@ nc4_get_vara(NC_FILE_INFO_T *nc, int ncid, int varid, const size_t *startp,
|
||||
|
||||
hid_t file_spaceid = 0, mem_spaceid = 0;
|
||||
hid_t xfer_plistid = 0;
|
||||
hid_t hdf_datasetid;
|
||||
size_t file_type_size;
|
||||
|
||||
hsize_t *xtend_size = NULL, count[NC_MAX_VAR_DIMS];
|
||||
|
@ -610,7 +610,6 @@ INPUT = \
|
||||
@abs_top_srcdir@/libdispatch/dparallel.c \
|
||||
@abs_top_srcdir@/libdispatch/derror.c \
|
||||
@abs_top_srcdir@/libdispatch/dv2i.c \
|
||||
@abs_top_srcdir@/libdispatch/nc4.c \
|
||||
@abs_top_srcdir@/libsrc4/nc4file.c \
|
||||
@abs_top_srcdir@/ncdump/ncdump.c \
|
||||
@abs_top_srcdir@/ncdump/nccopy.c
|
||||
|
@ -23,7 +23,7 @@ variables:
|
||||
:history = "This is an example of a multi-line global\n",
|
||||
"attribute. It could be used for representing the\n",
|
||||
"processing history of the data, for example." ;
|
||||
:_DODS_Unlimited_Dimension = "k" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "k" ;
|
||||
data:
|
||||
|
||||
l = 10, 9, 8 ;
|
||||
|
@ -23,7 +23,7 @@ variables:
|
||||
:history = "This is an example of a multi-line global\n",
|
||||
"attribute. It could be used for representing the\n",
|
||||
"processing history of the data, for example." ;
|
||||
:_DODS_Unlimited_Dimension = "k" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "k" ;
|
||||
data:
|
||||
|
||||
l = 10, 9, 8 ;
|
||||
|
@ -13,6 +13,13 @@ variables:
|
||||
|
||||
// global attributes:
|
||||
:Server = "DODS FreeFrom based on FFND release 4.2.3" ;
|
||||
:DODS_Time.hours_variable = "GSO_AVHRR.hh" ;
|
||||
:DODS_Time.minutes_variable = "GSO_AVHRR.mm" ;
|
||||
:DODS_Time.seconds_variable = "GSO_AVHRR.ss" ;
|
||||
:DODS_Time.gmt_time = "true" ;
|
||||
:DODS_Date.year_variable = "GSO_AVHRR.year" ;
|
||||
:DODS_Date.year_base = 1900 ;
|
||||
:DODS_Date.year_day_variable = "GSO_AVHRR.day_num" ;
|
||||
data:
|
||||
|
||||
GSO_AVHRR.satellite =
|
||||
|
@ -23,7 +23,7 @@ variables:
|
||||
:history = "This is an example of a multi-line global\n",
|
||||
"attribute. It could be used for representing the\n",
|
||||
"processing history of the data, for example." ;
|
||||
:_DODS_Unlimited_Dimension = "k" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "k" ;
|
||||
data:
|
||||
|
||||
l = 10, 9, 8 ;
|
||||
|
@ -16,7 +16,7 @@ variables:
|
||||
|
||||
// global attributes:
|
||||
:history = "FERRET V3.20 (development) 24-Jan-95" ;
|
||||
:_DODS_Unlimited_Dimension = "TIME" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "TIME" ;
|
||||
data:
|
||||
|
||||
TIME = 366, 1096.485, 1826.97, 2557.455, 3287.94, 4018.425, 4748.91,
|
||||
|
@ -25,7 +25,7 @@ variables:
|
||||
// global attributes:
|
||||
:base_time = "88- 10-00:00:00" ;
|
||||
:title = " FNOC UV wind components from 1988- 10 to 1988- 13." ;
|
||||
:_DODS_Unlimited_Dimension = "time_a" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time_a" ;
|
||||
data:
|
||||
|
||||
u =
|
||||
|
@ -328,7 +328,7 @@ variables:
|
||||
:history = "History global attribute.\n",
|
||||
"" ;
|
||||
:julian_day = 200000.04 ;
|
||||
:_DODS_Unlimited_Dimension = "time" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time" ;
|
||||
data:
|
||||
|
||||
lat = _, _ ;
|
||||
|
@ -348,7 +348,7 @@ variables:
|
||||
:history = "History global attribute.\n",
|
||||
"" ;
|
||||
:julian_day = 200000.04 ;
|
||||
:_DODS_Unlimited_Dimension = "time" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time" ;
|
||||
data:
|
||||
|
||||
lat = -90, 90 ;
|
||||
|
@ -330,7 +330,7 @@ variables:
|
||||
:history = "History global attribute.\n",
|
||||
"" ;
|
||||
:julian_day = 200000.04 ;
|
||||
:_DODS_Unlimited_Dimension = "time" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time" ;
|
||||
data:
|
||||
|
||||
lat = _, _ ;
|
||||
|
@ -328,7 +328,7 @@ variables:
|
||||
:history = "History global attribute.\n",
|
||||
"" ;
|
||||
:julian_day = 200000.04 ;
|
||||
:_DODS_Unlimited_Dimension = "time" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time" ;
|
||||
data:
|
||||
|
||||
lat = -90, 90 ;
|
||||
|
@ -11,7 +11,7 @@ variables:
|
||||
:history = "History global attribute.\n",
|
||||
"" ;
|
||||
:julian_day = 200000.04 ;
|
||||
:_DODS_Unlimited_Dimension = "time" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "time" ;
|
||||
data:
|
||||
|
||||
v = 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 ;
|
||||
|
@ -158,7 +158,7 @@ variables:
|
||||
:Gi = -2147483648, 2147483647, -2147483648, 2147483647 ;
|
||||
:Gf = -3.402823e+38f, 3.402823e+38f, -3.402823e+38f, 3.402823e+38f, 531.f ;
|
||||
:Gd = -1.79769313486232e+308, 1.79769313486232e+308, -1., 1., 660., 650. ;
|
||||
:_DODS_Unlimited_Dimension = "Dr" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "Dr" ;
|
||||
data:
|
||||
|
||||
c = "\002" ;
|
||||
|
@ -158,7 +158,7 @@ variables:
|
||||
:Gi = -2147483648, 2147483647, -2147483648, 2147483647 ;
|
||||
:Gf = -3.402823e+38f, 3.402823e+38f, -3.402823e+38f, 3.402823e+38f, 531.f ;
|
||||
:Gd = -1.79769313486232e+308, 1.79769313486232e+308, -1., 1., 660., 650. ;
|
||||
:_DODS_Unlimited_Dimension = "Dr" ;
|
||||
:DODS_EXTRA.Unlimited_Dimension = "Dr" ;
|
||||
data:
|
||||
|
||||
c = "\002" ;
|
||||
|
@ -230,7 +230,7 @@ if test 1 = 1; then
|
||||
echo "*** PASS: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test $isxfail = 1 ; then
|
||||
echo "*** XFAIL: ${x}"
|
||||
echo "*** XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "*** FAIL: ${x}"
|
||||
|
@ -45,7 +45,7 @@ for x in ${TESTSET} ; do
|
||||
test $verbose = 1 && echo "*** SUCCEED: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test "x${isxfail}" = "x1" ; then
|
||||
echo "*** XFAIL: ${x}"
|
||||
echo "*** XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "*** FAIL: ${x}"
|
||||
|
@ -156,7 +156,7 @@ if test 1 = 1; then
|
||||
echo "SUCCEED: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test $isxfail = 1 ; then
|
||||
echo "XFAIL: ${x}"
|
||||
echo "XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "FAIL: ${x}"
|
||||
|
@ -157,7 +157,7 @@ if test 1 = 1; then
|
||||
echo "SUCCEED: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test $isxfail = 1 ; then
|
||||
echo "XFAIL: ${x}"
|
||||
echo "XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "FAIL: ${x}"
|
||||
|
@ -151,7 +151,7 @@ if test 1 = 1; then
|
||||
echo "SUCCEED: ${x}"
|
||||
passcount=`expr $passcount + 1`
|
||||
elif test $isxfail = 1 ; then
|
||||
echo "XFAIL: ${x}"
|
||||
echo "XFAIL : ${x}"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
else
|
||||
echo "FAIL: ${x}"
|
||||
|
@ -386,9 +386,9 @@ so the names of variables, dimensions, and attributes must not be
|
||||
primitive type names. In declarations, type names may be specified
|
||||
in either upper or lower case.
|
||||
.LP
|
||||
Bytes differ from characters in that they are intended to hold a full eight
|
||||
Bytes are intended to hold a full eight
|
||||
bits of data, and the zero byte has no special significance, as it
|
||||
does for character data.
|
||||
mays for character data.
|
||||
\fBncgen\fP converts \fBbyte\fP declarations to \fBchar\fP
|
||||
declarations in the output C code and to the nonstandard \fBBYTE\fP
|
||||
declaration in output Fortran code.
|
||||
@ -430,6 +430,24 @@ The unsigned counterparts of the above integer types
|
||||
are mapped to the corresponding unsigned C types.
|
||||
Their ranges are suitably modified to start at zero.
|
||||
.LP
|
||||
The technical interpretation of the char type is that it is an unsigned
|
||||
8-bit value. The encoding of the 256 possible values
|
||||
is unspecified by default. A variable of char type
|
||||
may be marked with an "_Encoding" attribute to indicate
|
||||
the character set to be used: US-ASCII, ISO-8859-1, etc.
|
||||
Note that specifying the encoding of UTF-8 is equivalent to
|
||||
specifying US-ASCII
|
||||
This is because multi-byte UTF-8 characters cannot
|
||||
be stored in an 8-bit character. The only legal
|
||||
single byte UTF-8 values are by definition
|
||||
the 7-bit US-ASCII encoding with the top bit set to zero.
|
||||
.LP
|
||||
Strings are assumed by default to be encoded using UTF-8.
|
||||
Note that this means that multi-byte UTF-8 encodings may
|
||||
be present in the string, so it is possible that the number
|
||||
of distinct UTF-8 characters in a string is smaller than
|
||||
the number of 8-bit bytes used to store the string.
|
||||
.LP
|
||||
.SS "CDL Constants"
|
||||
.LP
|
||||
Constants assigned to attributes or variables may be of any of the
|
||||
@ -453,24 +471,6 @@ constants include:
|
||||
.fi
|
||||
.RE
|
||||
.LP
|
||||
Character constants are enclosed in double quotes. A character array
|
||||
may be represented as a string enclosed in double quotes. The usual C
|
||||
string escape conventions are honored. For example
|
||||
.RS
|
||||
.nf
|
||||
"a" // ASCII `a'
|
||||
"Two\\nlines\\n" // a 10-character string with two embedded newlines
|
||||
"a bell:\\007" // a string containing an ASCII bell
|
||||
.fi
|
||||
.RE
|
||||
Note that the netCDF character array "a" would fit in a one-element
|
||||
variable, since no terminating NULL character is assumed. However, a zero
|
||||
byte in a character array is interpreted as the end of the significant
|
||||
characters by the \fBncdump\fP program, following the C convention.
|
||||
Therefore, a NULL byte should not be embedded in a character string unless
|
||||
at the end: use the \fIbyte\fP data type instead for byte arrays that
|
||||
contain the zero byte.
|
||||
.LP
|
||||
\fIshort\fP integer constants are intended for representing 16-bit
|
||||
signed quantities. The form of a \fIshort\fP constant is an integer
|
||||
constant with an `s' or `S' appended. If a \fIshort\fP constant
|
||||
@ -547,12 +547,53 @@ the character 'U' or 'u' between the constant and any trailing
|
||||
size specifier. Thus one could say
|
||||
10U, 100us, 100000ul, or 1000000ull, for example.
|
||||
.LP
|
||||
Single character constants may be enclosed in single quotes.
|
||||
If a sequence of one or more characters is enclosed
|
||||
in double quotes, then its interpretation must be inferred
|
||||
from the context. If the dataset is created using the netCDF
|
||||
classic model, then all such constants are interpreted
|
||||
as a character array, so each character in the constant
|
||||
is interpreted as if it were a single character.
|
||||
If the dataset is netCDF extended, then the constant may
|
||||
be interpreted as for the classic model or as a true string
|
||||
(see below) depending on the type of the attribute or variable
|
||||
into which the string is contained.
|
||||
.LP
|
||||
The interpretation of char constants is that those
|
||||
that are in the printable ASCII range (' '..'~') are assumed to
|
||||
be encoded as the 1-byte subset ofUTF-8, which is equivalent to US-ASCII.
|
||||
In all cases, the usual C string escape conventions are honored
|
||||
for values from 0 thru 127. Values greater than 127 are allowed,
|
||||
but their encoding is undefined.
|
||||
For netCDF extended, the use of the char type is deprecated
|
||||
in favor of the string type.
|
||||
.LP
|
||||
Some character constant examples are as follows.
|
||||
.RS
|
||||
.nf
|
||||
'a' // ASCII `a'
|
||||
"a" // equivalent to 'a'
|
||||
"Two\\nlines\\n" // a 10-character string with two embedded newlines
|
||||
"a bell:\\007" // a string containing an ASCII bell
|
||||
.fi
|
||||
.RE
|
||||
Note that the netCDF character array "a" would fit in a one-element
|
||||
variable, since no terminating NULL character is assumed. However, a zero
|
||||
byte in a character array is interpreted as the end of the significant
|
||||
characters by the \fBncdump\fP program, following the C convention.
|
||||
Therefore, a NULL byte should not be embedded in a character string unless
|
||||
at the end: use the \fIbyte\fP data type instead for byte arrays that
|
||||
contain the zero byte.
|
||||
.LP
|
||||
\fIString\fP constants are, like character constants,
|
||||
represented using double quotes. This represents a potential
|
||||
ambiguity since a multi-character string may also indicate
|
||||
a dimensioned character value. Disambiguation usually occurs
|
||||
by context, but care should be taken to specify the\fIstring\fP
|
||||
type to ensure the proper choice.
|
||||
String constants are assumed to always be UTF-8 encoded. This
|
||||
specifically means that the string constant may actually
|
||||
contain multi-byte UTF-8 characters.
|
||||
.LP
|
||||
\fIOpaque\fP constants are represented as
|
||||
sequences of hexadecimal digits preceded by 0X or 0x: 0xaa34ffff,
|
||||
|
@ -6,7 +6,7 @@
|
||||
*********************************************************************/
|
||||
|
||||
/* Problems:
|
||||
1. Ideally, we assume the input is true ut8.
|
||||
1. We assume the input is true utf8.
|
||||
Unfortunately, we may actually get iso-latin-8859-1.
|
||||
This means that there will be ambiguity about the characters
|
||||
in the range 128-255 because they will look like n-byte unicode
|
||||
@ -24,7 +24,9 @@
|
||||
http://www.w3.org/2005/03/23-lex-U
|
||||
We include lexical definitions for all three, but use the second version.
|
||||
4. Single character constants enclosed in '...' cannot be
|
||||
utf-8, so we assume they are the one case where US-Ascii (7-bit) is used.
|
||||
utf-8, so we assume they are by default encoded using the 1-byte
|
||||
subset of utf-8. It turns out that this subset is in fact
|
||||
equivalent to US-Ascii (7-bit).
|
||||
We could use ISO-8859-1, but that conflicts with UTF-8 above value 127.
|
||||
*/
|
||||
|
||||
|
65
oc2/Make0
Executable file
65
oc2/Make0
Executable file
@ -0,0 +1,65 @@
|
||||
THISDIR=../oc2
|
||||
OCDIR=/home/dmh/svn/oc2.0
|
||||
|
||||
# Make consistent with Makefile.am
|
||||
SRC=oc.c \
|
||||
daplex.c dapparse.c daptab.c \
|
||||
occlientparams.c occompile.c occurlfunctions.c \
|
||||
ocdata.c ocdebug.c ocdump.c \
|
||||
ocinternal.c ocnode.c \
|
||||
ochttp.c \
|
||||
ocrc.c ocread.c ocutil.c \
|
||||
ocbytes.c oclist.c ocuri.c oclog.c \
|
||||
xxdr.c
|
||||
|
||||
HDRS=oc.h ocx.h \
|
||||
dapparselex.h daptab.h \
|
||||
occlientparams.h occompile.h occonstraints.h occurlfunctions.h \
|
||||
ocdata.h ocdatatypes.h ocdebug.h ocdump.h \
|
||||
ocinternal.h ocnode.h \
|
||||
ochttp.h ocrc.h ocread.h ocutil.h \
|
||||
ocbytes.h oclist.h ocuri.h oclog.h \
|
||||
xxdr.h
|
||||
|
||||
FILES=${HDRS} ${SRC} dap.y
|
||||
|
||||
all::
|
||||
|
||||
makeoc::
|
||||
rm -f ${THISDIR}/*.[chy]
|
||||
for file in ${FILES} ; do \
|
||||
f="${OCDIR}/$$file" ; \
|
||||
base=`basename $$f` ; \
|
||||
cat $$f | tr -d '
' >${THISDIR}/$$base; \
|
||||
done
|
||||
rm -f ocdebug.h
|
||||
sed -e 's|^[#]if 1|#if 0|g' \
|
||||
< ${OCDIR}/ocdebug.h | tr -d '\r' >./ocdebug.h
|
||||
# This should match the bison command in Makefile.am
|
||||
rm -f dap.tab.c dap.tab.h
|
||||
bison --debug -d -p dap dap.y
|
||||
mv dap.tab.c daptab.c; mv dap.tab.h daptab.h
|
||||
|
||||
diffoc::
|
||||
if ! test -e ${OCDIR} ; then echo "${OCDIR} not found"; exit ; fi
|
||||
for file in ${FILES} ; do \
|
||||
f="${OCDIR}/$$file" ; \
|
||||
x=`basename $$f | tr -d '
' ` ; \
|
||||
if test "x$${x}" = "xdaptab.c" -o "x$${x}" = "xdaptab.h" ; then echo "ignore: $${x}"; continue; fi ;\
|
||||
if test -e ${THISDIR}/$$x -a -e ${OCDIR}/$$x ; then \
|
||||
diff --brief -wBb ${THISDIR}/$$x $$f ; \
|
||||
else \
|
||||
echo "Only in ${OCDIR}: $$x"; \
|
||||
fi; \
|
||||
done
|
||||
for file in ${FILES} ; do \
|
||||
f="${OCDIR}/$$file" ; \
|
||||
x=`basename $$f|tr -d '
' ` ; \
|
||||
if test "x$${x}" = "xdaptab.c" -o "x$${x}" = "xdaptab.h" ; then echo "ignore: $${x}"; continue; fi ;\
|
||||
if test -e ${THISDIR}/$$x -a -e ${OCDIR}/$$x ; then \
|
||||
if ! diff --brief -wBb ${THISDIR}/$$x $$f > /dev/null ; then \
|
||||
echo diff -wBb ${THISDIR}/$$x $$f ;\
|
||||
diff -w ${THISDIR}/$$x $$f ; \
|
||||
fi; \
|
||||
fi; \
|
||||
done
|
51
oc2/Makefile.am
Executable file
51
oc2/Makefile.am
Executable file
@ -0,0 +1,51 @@
|
||||
## This is a automake file, part of Unidata's netCDF package.
|
||||
# Copyright 2005, see the COPYRIGHT file for more information.
|
||||
|
||||
# This automake file generates the Makefile to build netCDF-4. The
|
||||
# generated makefile is not run unless the user selected to build
|
||||
# netCDF-4.
|
||||
|
||||
# $Id: Makefile.am,v 1.1 2010/05/23 21:05:33 dmh Exp $
|
||||
|
||||
# Cause C preprocessor to search current and parent directory.
|
||||
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/include
|
||||
|
||||
# OC Sources; include the daptab.[ch] to avoid the need for bison by user
|
||||
SRC=oc.c \
|
||||
daplex.c dapparse.c daptab.c \
|
||||
occlientparams.c occompile.c occurlfunctions.c \
|
||||
ocdata.c ocdebug.c ocdump.c \
|
||||
ocinternal.c ocnode.c \
|
||||
ochttp.c \
|
||||
ocrc.c ocread.c ocutil.c \
|
||||
ocbytes.c oclist.c ocuri.c oclog.c \
|
||||
xxdr.c
|
||||
|
||||
HDRS=oc.h ocx.h \
|
||||
dapparselex.h daptab.h \
|
||||
occlientparams.h occompile.h occonstraints.h occurlfunctions.h \
|
||||
ocdata.h ocdatatypes.h ocdebug.h ocdump.h \
|
||||
ocinternal.h ocnode.h \
|
||||
ochttp.h ocrc.h ocread.h ocutil.h \
|
||||
ocbytes.h oclist.h ocuri.h oclog.h \
|
||||
xxdr.h
|
||||
|
||||
if BUILD_DAP
|
||||
noinst_LTLIBRARIES = liboc.la
|
||||
liboc_la_SOURCES = $(SRC) $(HDRS)
|
||||
liboc_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
endif
|
||||
|
||||
# These rule are used if someone wants to rebuild the grammar files.
|
||||
# Otherwise never invoked, but records how to do it.
|
||||
# BTW: note that renaming is essential because otherwise
|
||||
# autoconf will forcibly delete files of the name *.tab.*
|
||||
|
||||
.PHONEY: bison
|
||||
|
||||
bison:: dap.y
|
||||
rm -f dap.tab.c dap.tab.h
|
||||
bison --debug -d -p dap dap.y
|
||||
mv dap.tab.c daptab.c; mv dap.tab.h daptab.h
|
||||
|
||||
|
272
oc2/dap.y
Normal file
272
oc2/dap.y
Normal file
@ -0,0 +1,272 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
/*The lines down to DO NOT DELETE ... comment are specific to the C Parser.
|
||||
They will be commennted out when building a java parser.
|
||||
*/
|
||||
%error-verbose
|
||||
%pure-parser
|
||||
%lex-param {DAPparsestate* parsestate}
|
||||
%parse-param {DAPparsestate* parsestate}
|
||||
%{
|
||||
#include "config.h"
|
||||
#include "dapparselex.h"
|
||||
int dapdebug = 0;
|
||||
%}
|
||||
|
||||
/*DO NOT DELETE THIS LINE*/
|
||||
|
||||
%token SCAN_ALIAS
|
||||
%token SCAN_ARRAY
|
||||
%token SCAN_ATTR
|
||||
%token SCAN_BYTE
|
||||
%token SCAN_CODE
|
||||
%token SCAN_DATASET
|
||||
%token SCAN_DATA
|
||||
|
||||
%token SCAN_ERROR
|
||||
%token SCAN_FLOAT32
|
||||
%token SCAN_FLOAT64
|
||||
%token SCAN_GRID
|
||||
%token SCAN_INT16
|
||||
%token SCAN_INT32
|
||||
%token SCAN_MAPS
|
||||
%token SCAN_MESSAGE
|
||||
%token SCAN_SEQUENCE
|
||||
%token SCAN_STRING
|
||||
%token SCAN_STRUCTURE
|
||||
%token SCAN_UINT16
|
||||
%token SCAN_UINT32
|
||||
%token SCAN_URL
|
||||
/* For errorbody */
|
||||
%token SCAN_PTYPE
|
||||
%token SCAN_PROG
|
||||
|
||||
/* Non-keywords */
|
||||
%token WORD_WORD WORD_STRING
|
||||
|
||||
%start start
|
||||
|
||||
%%
|
||||
|
||||
start:
|
||||
dataset datasetbody
|
||||
| dataset datasetbody SCAN_DATA
|
||||
| attr attributebody
|
||||
| err errorbody
|
||||
| error {dap_unrecognizedresponse(parsestate); YYABORT;}
|
||||
;
|
||||
|
||||
dataset:
|
||||
SCAN_DATASET
|
||||
{dap_tagparse(parsestate,SCAN_DATASET);}
|
||||
;
|
||||
attr:
|
||||
SCAN_ATTR
|
||||
{dap_tagparse(parsestate,SCAN_ATTR);}
|
||||
;
|
||||
err:
|
||||
SCAN_ERROR
|
||||
{dap_tagparse(parsestate,SCAN_ERROR);}
|
||||
;
|
||||
|
||||
datasetbody:
|
||||
'{' declarations '}' datasetname ';'
|
||||
{dap_datasetbody(parsestate,$4,$2);}
|
||||
;
|
||||
|
||||
|
||||
declarations:
|
||||
/* empty */ {$$=dap_declarations(parsestate,null,null);}
|
||||
| declarations declaration {$$=dap_declarations(parsestate,$1,$2);}
|
||||
;
|
||||
|
||||
/* 01/21/08: James says: no dimensions for grids or sequences */
|
||||
/* 05/08/09: James says: no duplicate map names */
|
||||
declaration:
|
||||
base_type var_name array_decls ';'
|
||||
{$$=dap_makebase(parsestate,$2,$1,$3);}
|
||||
| SCAN_STRUCTURE '{' declarations '}' var_name array_decls ';'
|
||||
{if(($$=dap_makestructure(parsestate,$5,$6,$3))==null) {YYABORT;}}
|
||||
| SCAN_SEQUENCE '{' declarations '}' var_name ';'
|
||||
{if(($$=dap_makesequence(parsestate,$5,$3))==null) {YYABORT;}}
|
||||
| SCAN_GRID '{' SCAN_ARRAY ':' declaration SCAN_MAPS ':'
|
||||
declarations '}' var_name ';'
|
||||
{if(($$=dap_makegrid(parsestate,$10,$5,$8))==null) {YYABORT;}}
|
||||
| error
|
||||
{daperror(parsestate,"Unrecognized type"); YYABORT;}
|
||||
;
|
||||
|
||||
|
||||
base_type:
|
||||
SCAN_BYTE {$$=(Object)SCAN_BYTE;}
|
||||
| SCAN_INT16 {$$=(Object)SCAN_INT16;}
|
||||
| SCAN_UINT16 {$$=(Object)SCAN_UINT16;}
|
||||
| SCAN_INT32 {$$=(Object)SCAN_INT32;}
|
||||
| SCAN_UINT32 {$$=(Object)SCAN_UINT32;}
|
||||
| SCAN_FLOAT32 {$$=(Object)SCAN_FLOAT32;}
|
||||
| SCAN_FLOAT64 {$$=(Object)SCAN_FLOAT64;}
|
||||
| SCAN_URL {$$=(Object)SCAN_URL;}
|
||||
| SCAN_STRING {$$=(Object)SCAN_STRING;}
|
||||
;
|
||||
|
||||
array_decls:
|
||||
/* empty */ {$$=dap_arraydecls(parsestate,null,null);}
|
||||
| array_decls array_decl {$$=dap_arraydecls(parsestate,$1,$2);}
|
||||
;
|
||||
|
||||
array_decl:
|
||||
'[' WORD_WORD ']' {$$=dap_arraydecl(parsestate,null,$2);}
|
||||
| '[' '=' WORD_WORD ']' {$$=dap_arraydecl(parsestate,null,$3);}
|
||||
| '[' name '=' WORD_WORD ']' {$$=dap_arraydecl(parsestate,$2,$4);}
|
||||
| error
|
||||
{daperror(parsestate,"Illegal dimension declaration"); YYABORT;}
|
||||
;
|
||||
|
||||
datasetname:
|
||||
var_name {$$=$1;}
|
||||
| error
|
||||
{daperror(parsestate,"Illegal dataset declaration"); YYABORT;}
|
||||
;
|
||||
|
||||
var_name: name {$$=$1;};
|
||||
|
||||
attributebody:
|
||||
'{' attr_list '}' {dap_attributebody(parsestate,$2);}
|
||||
| error
|
||||
{daperror(parsestate,"Illegal DAS body"); YYABORT;}
|
||||
;
|
||||
|
||||
attr_list:
|
||||
/* empty */ {$$=dap_attrlist(parsestate,null,null);}
|
||||
| attr_list attribute {$$=dap_attrlist(parsestate,$1,$2);}
|
||||
;
|
||||
|
||||
attribute:
|
||||
alias ';' {$$=null;} /* ignored */
|
||||
| SCAN_BYTE name bytes ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_BYTE);}
|
||||
| SCAN_INT16 name int16 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_INT16);}
|
||||
| SCAN_UINT16 name uint16 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_UINT16);}
|
||||
| SCAN_INT32 name int32 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_INT32);}
|
||||
| SCAN_UINT32 name uint32 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_UINT32);}
|
||||
| SCAN_FLOAT32 name float32 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_FLOAT32);}
|
||||
| SCAN_FLOAT64 name float64 ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_FLOAT64);}
|
||||
| SCAN_STRING name strs ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_STRING);}
|
||||
| SCAN_URL name urls ';'
|
||||
{$$=dap_attribute(parsestate,$2,$3,(Object)SCAN_URL);}
|
||||
| name '{' attr_list '}' {$$=dap_attrset(parsestate,$1,$3);}
|
||||
| error
|
||||
{daperror(parsestate,"Illegal attribute"); YYABORT;}
|
||||
;
|
||||
|
||||
bytes:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_BYTE);}
|
||||
| bytes ',' WORD_WORD
|
||||
{$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_BYTE);}
|
||||
;
|
||||
int16:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_INT16);}
|
||||
| int16 ',' WORD_WORD
|
||||
{$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_INT16);}
|
||||
;
|
||||
uint16:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_UINT16);}
|
||||
| uint16 ',' WORD_WORD
|
||||
{$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_UINT16);}
|
||||
;
|
||||
int32:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_INT32);}
|
||||
| int32 ',' WORD_WORD
|
||||
{$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_INT32);}
|
||||
;
|
||||
uint32:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_UINT32);}
|
||||
| uint32 ',' WORD_WORD {$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_UINT32);}
|
||||
;
|
||||
float32:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_FLOAT32);}
|
||||
| float32 ',' WORD_WORD {$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_FLOAT32);}
|
||||
;
|
||||
float64:
|
||||
WORD_WORD {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_FLOAT64);}
|
||||
| float64 ',' WORD_WORD {$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_FLOAT64);}
|
||||
;
|
||||
strs:
|
||||
str_or_id {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_STRING);}
|
||||
| strs ',' str_or_id {$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_STRING);}
|
||||
;
|
||||
|
||||
urls:
|
||||
url {$$=dap_attrvalue(parsestate,null,$1,(Object)SCAN_URL);}
|
||||
| urls ',' url {$$=dap_attrvalue(parsestate,$1,$3,(Object)SCAN_URL);}
|
||||
;
|
||||
|
||||
url:
|
||||
name {$$=$1;}
|
||||
;
|
||||
|
||||
str_or_id:
|
||||
name {$$=$1;}
|
||||
| WORD_STRING {$$=$1;}
|
||||
;
|
||||
|
||||
/* Not used
|
||||
float_or_int:
|
||||
WORD_INT {$$=$1;}
|
||||
| WORD_DOUBLE {$$=$1;}
|
||||
;
|
||||
*/
|
||||
|
||||
alias:
|
||||
SCAN_ALIAS WORD_WORD WORD_WORD {$$=$2; $$=$3; $$=null;} /* Alias is ignored */
|
||||
;
|
||||
|
||||
errorbody:
|
||||
'{' errorcode errormsg errorptype errorprog '}' ';'
|
||||
{dap_errorbody(parsestate,$2,$3,$4,$5);}
|
||||
;
|
||||
|
||||
errorcode: /*empty*/ {$$=null;} | SCAN_CODE '=' WORD_WORD ';' {$$=$3;}
|
||||
errormsg: /*empty*/ {$$=null;} | SCAN_MESSAGE '=' WORD_WORD ';' {$$=$3;}
|
||||
errorptype: /*empty*/ {$$=null;} | SCAN_PTYPE '=' WORD_WORD ';' {$$=$3;}
|
||||
errorprog : /*empty*/ {$$=null;} | SCAN_PROG '=' WORD_WORD ';' {$$=$3;}
|
||||
|
||||
/* Note that variable names like "byte" are legal names
|
||||
and are disambiguated by context
|
||||
*/
|
||||
name:
|
||||
WORD_WORD {$$=dapdecode(parsestate->lexstate,$1);}
|
||||
| SCAN_ALIAS {$$=strdup("alias");}
|
||||
| SCAN_ARRAY {$$=strdup("array");}
|
||||
| SCAN_ATTR {$$=strdup("attributes");}
|
||||
| SCAN_BYTE {$$=strdup("byte");}
|
||||
| SCAN_DATASET {$$=strdup("dataset");}
|
||||
| SCAN_DATA {$$=strdup("data");}
|
||||
| SCAN_ERROR {$$=strdup("error");}
|
||||
| SCAN_FLOAT32 {$$=strdup("float32");}
|
||||
| SCAN_FLOAT64 {$$=strdup("float64");}
|
||||
| SCAN_GRID {$$=strdup("grid");}
|
||||
| SCAN_INT16 {$$=strdup("int16");}
|
||||
| SCAN_INT32 {$$=strdup("int32");}
|
||||
| SCAN_MAPS {$$=strdup("maps");}
|
||||
| SCAN_SEQUENCE {$$=strdup("sequence");}
|
||||
| SCAN_STRING {$$=strdup("string");}
|
||||
| SCAN_STRUCTURE {$$=strdup("structure");}
|
||||
| SCAN_UINT16 {$$=strdup("uint16");}
|
||||
| SCAN_UINT32 {$$=strdup("uint32");}
|
||||
| SCAN_URL {$$=strdup("url");}
|
||||
| SCAN_CODE {$$=strdup("code");}
|
||||
| SCAN_MESSAGE {$$=strdup("message");}
|
||||
| SCAN_PROG {$$=strdup("program");}
|
||||
| SCAN_PTYPE {$$=strdup("program_type");}
|
||||
;
|
||||
|
||||
%%
|
350
oc2/daplex.c
Normal file
350
oc2/daplex.c
Normal file
@ -0,0 +1,350 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include <strings.h>
|
||||
#include "dapparselex.h"
|
||||
|
||||
#undef URLCVT /* NEVER turn this on */
|
||||
#define DAP2ENCODE
|
||||
|
||||
/* Forward */
|
||||
static void dumptoken(DAPlexstate* lexstate);
|
||||
static void dapaddyytext(DAPlexstate* lex, int c);
|
||||
#ifndef DAP2ENCODE
|
||||
static int tohex(int c);
|
||||
#endif
|
||||
|
||||
/****************************************************/
|
||||
|
||||
#ifdef INFORMATIONAL
|
||||
/* Set of all ascii printable characters */
|
||||
static char ascii[] = " !\"#$%&'()*+,-./:;<=>?@[]\\^_`|{}~";
|
||||
|
||||
/* Define the set of legal nonalphanum characters as specified in the DAP2 spec. */
|
||||
static char* daplegal ="_!~*'-\"";
|
||||
#endif
|
||||
|
||||
static char* ddsworddelims =
|
||||
"{}[]:;=,";
|
||||
|
||||
/* Define 1 and > 1st legal characters */
|
||||
static char* ddswordchars1 =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_/%\\.*";
|
||||
static char* ddswordcharsn =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_/%\\.*#";
|
||||
static char* daswordcharsn =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_/%\\.*#:";
|
||||
static char* cewordchars1 =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_/%\\";
|
||||
static char* cewordcharsn =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+_/%\\";
|
||||
|
||||
/* Current sets of legal characters */
|
||||
/*
|
||||
static char* wordchars1 = NULL;
|
||||
static char* wordcharsn = NULL;
|
||||
static char* worddelims = NULL;
|
||||
*/
|
||||
|
||||
static char* keywords[] = {
|
||||
"alias",
|
||||
"array",
|
||||
"attributes",
|
||||
"byte",
|
||||
"dataset",
|
||||
"error",
|
||||
"float32",
|
||||
"float64",
|
||||
"grid",
|
||||
"int16",
|
||||
"int32",
|
||||
"maps",
|
||||
"sequence",
|
||||
"string",
|
||||
"structure",
|
||||
"uint16",
|
||||
"uint32",
|
||||
"url",
|
||||
"code",
|
||||
"message",
|
||||
"program_type",
|
||||
"program",
|
||||
NULL /* mark end of the keywords list */
|
||||
};
|
||||
|
||||
static int keytokens[] = {
|
||||
SCAN_ALIAS,
|
||||
SCAN_ARRAY,
|
||||
SCAN_ATTR,
|
||||
SCAN_BYTE,
|
||||
SCAN_DATASET,
|
||||
SCAN_ERROR,
|
||||
SCAN_FLOAT32,
|
||||
SCAN_FLOAT64,
|
||||
SCAN_GRID,
|
||||
SCAN_INT16,
|
||||
SCAN_INT32,
|
||||
SCAN_MAPS,
|
||||
SCAN_SEQUENCE,
|
||||
SCAN_STRING,
|
||||
SCAN_STRUCTURE,
|
||||
SCAN_UINT16,
|
||||
SCAN_UINT32,
|
||||
SCAN_URL,
|
||||
SCAN_CODE,
|
||||
SCAN_MESSAGE,
|
||||
SCAN_PTYPE,
|
||||
SCAN_PROG
|
||||
};
|
||||
|
||||
/**************************************************/
|
||||
|
||||
int
|
||||
daplex(YYSTYPE* lvalp, DAPparsestate* state)
|
||||
{
|
||||
DAPlexstate* lexstate = state->lexstate;
|
||||
int token;
|
||||
int c;
|
||||
unsigned int i;
|
||||
char* p;
|
||||
char* tmp;
|
||||
|
||||
token = 0;
|
||||
ocbytesclear(lexstate->yytext);
|
||||
/* invariant: p always points to current char */
|
||||
for(p=lexstate->next;token==0&&(c=*p);p++) {
|
||||
if(c == '\n') {
|
||||
lexstate->lineno++;
|
||||
} else if(c <= ' ' || c == '\177') {
|
||||
/* whitespace: ignore */
|
||||
} else if(c == '#') {
|
||||
/* single line comment */
|
||||
while((c=*(++p))) {if(c == '\n') break;}
|
||||
} else if(strchr(lexstate->worddelims,c) != NULL) {
|
||||
/* don't put in lexstate->yytext to avoid memory leak */
|
||||
token = c;
|
||||
} else if(c == '"') {
|
||||
int more = 1;
|
||||
/* We have a string token; will be reported as WORD_STRING */
|
||||
while(more && (c=*(++p))) {
|
||||
#ifdef DAP2ENCODE
|
||||
if(c == '"')
|
||||
more = 0;
|
||||
else if(c == '\\') {
|
||||
/* Remove spec ambiguity by convering \c to c
|
||||
for any character c */
|
||||
c=*(++p);
|
||||
if(c == '\0') more = 0;
|
||||
}
|
||||
#else /*Non-standard*/
|
||||
switch (c) {
|
||||
case '"': more=0; break;
|
||||
case '\\':
|
||||
c=*(++p);
|
||||
switch (c) {
|
||||
case 'r': c = '\r'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'f': c = '\f'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'x': {
|
||||
int d1,d2;
|
||||
c = '?';
|
||||
++p;
|
||||
d1 = tohex(*p++);
|
||||
if(d1 < 0) {
|
||||
daperror(state,"Illegal \\xDD in TOKEN_STRING");
|
||||
} else {
|
||||
d2 = tohex(*p++);
|
||||
if(d2 < 0) {
|
||||
daperror(state,"Illegal \\xDD in TOKEN_STRING");
|
||||
} else {
|
||||
c=(((unsigned int)d1)<<4) | (unsigned int)d2;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
#endif /*!DAP2ENCODE*/
|
||||
if(more) dapaddyytext(lexstate,c);
|
||||
}
|
||||
token=WORD_STRING;
|
||||
} else if(strchr(lexstate->wordchars1,c) != NULL) {
|
||||
int isdatamark = 0;
|
||||
/* we have a WORD_WORD */
|
||||
dapaddyytext(lexstate,c);
|
||||
while((c=*(++p))) {
|
||||
#ifdef URLCVT
|
||||
if(c == '%' && p[1] != 0 && p[2] != 0
|
||||
&& strchr(hexdigits,p[1]) != NULL
|
||||
&& strchr(hexdigits,p[2]) != NULL) {
|
||||
int d1,d2;
|
||||
d1 = tohex(p[1]);
|
||||
d2 = tohex(p[2]);
|
||||
if(d1 >= 0 || d2 >= 0) {
|
||||
c=(((unsigned int)d1)<<4) | (unsigned int)d2;
|
||||
p+=2;
|
||||
}
|
||||
} else {
|
||||
if(strchr(lexstate->wordcharsn,c) == NULL) {p--; break;}
|
||||
}
|
||||
dapaddyytext(lexstate,c);
|
||||
#else
|
||||
if(strchr(lexstate->wordcharsn,c) == NULL) {p--; break;}
|
||||
dapaddyytext(lexstate,c);
|
||||
#endif
|
||||
}
|
||||
/* Special check for Data: */
|
||||
tmp = ocbytescontents(lexstate->yytext);
|
||||
if(strcmp(tmp,"Data")==0 && *p == ':') {
|
||||
dapaddyytext(lexstate,*p); p++;
|
||||
if(p[0] == '\n') {
|
||||
token = SCAN_DATA;
|
||||
isdatamark = 1;
|
||||
p++;
|
||||
} else if(p[0] == '\r' && p[1] == '\n') {
|
||||
token = SCAN_DATA;
|
||||
isdatamark = 1;
|
||||
p+=2;
|
||||
}
|
||||
}
|
||||
if(!isdatamark) {
|
||||
/* check for keyword */
|
||||
token=WORD_WORD; /* assume */
|
||||
for(i=0;;i++) {
|
||||
if(keywords[i] == NULL) break;
|
||||
if(strcasecmp(keywords[i],tmp)==0) {
|
||||
token=keytokens[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { /* illegal */
|
||||
}
|
||||
}
|
||||
lexstate->next = p;
|
||||
strncpy(lexstate->lasttokentext,ocbytescontents(lexstate->yytext),MAX_TOKEN_LENGTH);
|
||||
lexstate->lasttoken = token;
|
||||
if(ocdebug >= 2)
|
||||
dumptoken(lexstate);
|
||||
|
||||
/*Put return value onto Bison stack*/
|
||||
|
||||
if(ocbyteslength(lexstate->yytext) == 0)
|
||||
*lvalp = NULL;
|
||||
else {
|
||||
*lvalp = ocbytesdup(lexstate->yytext);
|
||||
oclistpush(lexstate->reclaim,(ocelem)*lvalp);
|
||||
}
|
||||
return token; /* Return the type of the token. */
|
||||
}
|
||||
|
||||
static void
|
||||
dapaddyytext(DAPlexstate* lex, int c)
|
||||
{
|
||||
ocbytesappend(lex->yytext,(char)c);
|
||||
}
|
||||
|
||||
#ifndef DAP2ENCODE
|
||||
static int
|
||||
tohex(int c)
|
||||
{
|
||||
if(c >= 'a' && c <= 'f') return (c - 'a') + 0xa;
|
||||
if(c >= 'A' && c <= 'F') return (c - 'A') + 0xa;
|
||||
if(c >= '0' && c <= '9') return (c - '0');
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
dumptoken(DAPlexstate* lexstate)
|
||||
{
|
||||
fprintf(stderr,"TOKEN = |%s|\n",ocbytescontents(lexstate->yytext));
|
||||
}
|
||||
|
||||
/*
|
||||
Simple lexer
|
||||
*/
|
||||
|
||||
void
|
||||
dapsetwordchars(DAPlexstate* lexstate, int kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case 0:
|
||||
lexstate->worddelims = ddsworddelims;
|
||||
lexstate->wordchars1 = ddswordchars1;
|
||||
lexstate->wordcharsn = ddswordcharsn;
|
||||
break;
|
||||
case 1:
|
||||
lexstate->worddelims = ddsworddelims;
|
||||
lexstate->wordchars1 = ddswordchars1;
|
||||
lexstate->wordcharsn = daswordcharsn;
|
||||
break;
|
||||
case 2:
|
||||
lexstate->worddelims = ddsworddelims;
|
||||
lexstate->wordchars1 = cewordchars1;
|
||||
lexstate->wordcharsn = cewordcharsn;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
daplexinit(char* input, DAPlexstate** lexstatep)
|
||||
{
|
||||
DAPlexstate* lexstate = (DAPlexstate*)malloc(sizeof(DAPlexstate));
|
||||
if(lexstatep) *lexstatep = lexstate;
|
||||
if(lexstate == NULL) return;
|
||||
memset((void*)lexstate,0,sizeof(DAPlexstate));
|
||||
lexstate->input = strdup(input);
|
||||
lexstate->next = lexstate->input;
|
||||
lexstate->yytext = ocbytesnew();
|
||||
lexstate->reclaim = oclistnew();
|
||||
dapsetwordchars(lexstate,0); /* Assume DDS */
|
||||
}
|
||||
|
||||
void
|
||||
daplexcleanup(DAPlexstate** lexstatep)
|
||||
{
|
||||
DAPlexstate* lexstate = *lexstatep;
|
||||
if(lexstate == NULL) return;
|
||||
if(lexstate->input != NULL) ocfree(lexstate->input);
|
||||
if(lexstate->reclaim != NULL) {
|
||||
while(oclistlength(lexstate->reclaim) > 0) {
|
||||
char* word = (char*)oclistpop(lexstate->reclaim);
|
||||
if(word) free(word);
|
||||
}
|
||||
oclistfree(lexstate->reclaim);
|
||||
}
|
||||
ocbytesfree(lexstate->yytext);
|
||||
free(lexstate);
|
||||
*lexstatep = NULL;
|
||||
}
|
||||
|
||||
/* Dap identifiers will come to us with some
|
||||
characters escaped using the URL notation of
|
||||
%HH. The assumption here is that any character
|
||||
that is encoded is left encoded, except as follows:
|
||||
1. if the encoded character is in fact a legal DAP2 character
|
||||
(alphanum+"_!~*'-\"") then it is decoded, otherwise not.
|
||||
*/
|
||||
#ifndef DECODE_IDENTIFIERS
|
||||
static char* decodelist =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!~*'-\"";
|
||||
#endif
|
||||
|
||||
char*
|
||||
dapdecode(DAPlexstate* lexstate, char* name)
|
||||
{
|
||||
char* decoded;
|
||||
#ifdef DECODE_IDENTIFIERS
|
||||
decoded = ocuridecode(name);
|
||||
#else
|
||||
decoded = ocuridecodeonly(name,decodelist);
|
||||
#endif
|
||||
oclistpush(lexstate->reclaim,(ocelem)decoded);
|
||||
return decoded;
|
||||
}
|
493
oc2/dapparse.c
Normal file
493
oc2/dapparse.c
Normal file
@ -0,0 +1,493 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "dapparselex.h"
|
||||
|
||||
/* Forward */
|
||||
|
||||
static void addedges(OCnode* node);
|
||||
static void setroot(OCnode*,OClist*);
|
||||
static int isglobalname(const char* name);
|
||||
static int isdodsname(const char* name);
|
||||
static OCnode* newocnode(char* name, OCtype octype, DAPparsestate* state);
|
||||
static OCtype octypefor(Object etype);
|
||||
static char* scopeduplicates(OClist* list);
|
||||
static int check_int32(char* val, long* value);
|
||||
|
||||
|
||||
/****************************************************/
|
||||
|
||||
/* Switch to DAS parsing SCAN_WORD definition */
|
||||
|
||||
/* Use the initial keyword to indicate what we are parsing */
|
||||
void
|
||||
dap_tagparse(DAPparsestate* state, int kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case SCAN_DATASET:
|
||||
case SCAN_ERROR:
|
||||
break;
|
||||
case SCAN_ATTR:
|
||||
dapsetwordchars(state->lexstate,1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"tagparse: Unknown tag argument: %d\n",kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Object
|
||||
dap_datasetbody(DAPparsestate* state, Object name, Object decls)
|
||||
{
|
||||
OCnode* root = newocnode((char*)name,OC_Dataset,state);
|
||||
root->subnodes = (OClist*)decls;
|
||||
OCASSERT((state->root == NULL));
|
||||
state->root = root;
|
||||
state->root->root = state->root; /* make sure to cross link */
|
||||
addedges(root);
|
||||
setroot(root,state->ocnodes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_attributebody(DAPparsestate* state, Object attrlist)
|
||||
{
|
||||
OCnode* node = newocnode(NULL,OC_Attributeset,state);
|
||||
OCASSERT((state->root == NULL));
|
||||
state->root = node;
|
||||
/* make sure to cross link */
|
||||
state->root->root = state->root;
|
||||
node->subnodes = (OClist*)attrlist;
|
||||
addedges(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
dap_errorbody(DAPparsestate* state,
|
||||
Object code, Object msg, Object ptype, Object prog)
|
||||
{
|
||||
state->svcerror = 1;
|
||||
state->code = nulldup((char*)code);
|
||||
state->message = nulldup((char*)msg);
|
||||
/* Ignore ptype and prog for now */
|
||||
}
|
||||
|
||||
void
|
||||
dap_unrecognizedresponse(DAPparsestate* state)
|
||||
{
|
||||
/* see if this is an HTTP error */
|
||||
unsigned int httperr = 0;
|
||||
int i;
|
||||
char iv[32];
|
||||
sscanf(state->lexstate->input,"%u ",&httperr);
|
||||
sprintf(iv,"%u",httperr);
|
||||
state->lexstate->next = state->lexstate->input;
|
||||
/* Limit the amount of input to prevent runaway */
|
||||
for(i=0;i<4096;i++) {if(state->lexstate->input[i] == '\0') break;}
|
||||
state->lexstate->input[i] = '\0';
|
||||
dap_errorbody(state,iv,state->lexstate->input,NULL,NULL);
|
||||
}
|
||||
|
||||
Object
|
||||
dap_declarations(DAPparsestate* state, Object decls, Object decl)
|
||||
{
|
||||
OClist* alist = (OClist*)decls;
|
||||
if(alist == NULL)
|
||||
alist = oclistnew();
|
||||
else
|
||||
oclistpush(alist,(ocelem)decl);
|
||||
return alist;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_arraydecls(DAPparsestate* state, Object arraydecls, Object arraydecl)
|
||||
{
|
||||
OClist* alist = (OClist*)arraydecls;
|
||||
if(alist == NULL)
|
||||
alist = oclistnew();
|
||||
else
|
||||
oclistpush(alist,(ocelem)arraydecl);
|
||||
return alist;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_arraydecl(DAPparsestate* state, Object name, Object size)
|
||||
{
|
||||
long value;
|
||||
OCnode* dim;
|
||||
if(!check_int32(size,&value))
|
||||
dap_parse_error(state,"Dimension not an integer");
|
||||
if(name != NULL)
|
||||
dim = newocnode((char*)name,OC_Dimension,state);
|
||||
else
|
||||
dim = newocnode(NULL,OC_Dimension,state);
|
||||
dim->dim.declsize = value;
|
||||
return dim;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_attrlist(DAPparsestate* state, Object attrlist, Object attrtuple)
|
||||
{
|
||||
OClist* alist = (OClist*)attrlist;
|
||||
if(alist == NULL)
|
||||
alist = oclistnew();
|
||||
else {
|
||||
char* dupname;
|
||||
if(attrtuple != NULL) {/* NULL=>alias encountered, ignore */
|
||||
oclistpush(alist,(ocelem)attrtuple);
|
||||
if((dupname=scopeduplicates(alist))!=NULL) {
|
||||
dap_parse_error(state,"Duplicate attribute names in same scope: %s",dupname);
|
||||
/* Remove this attribute */
|
||||
oclistpop(alist);
|
||||
}
|
||||
}
|
||||
}
|
||||
return alist;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_attrvalue(DAPparsestate* state, Object valuelist, Object value, Object etype)
|
||||
{
|
||||
OClist* alist = (OClist*)valuelist;
|
||||
if(alist == NULL) alist = oclistnew();
|
||||
/* Watch out for null values */
|
||||
if(value == NULL) value = "";
|
||||
oclistpush(alist,(ocelem)strdup(value));
|
||||
return alist;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_attribute(DAPparsestate* state, Object name, Object values, Object etype)
|
||||
{
|
||||
OCnode* att;
|
||||
att = newocnode((char*)name,OC_Attribute,state);
|
||||
att->etype = octypefor(etype);
|
||||
att->att.values = (OClist*)values;
|
||||
return att;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_attrset(DAPparsestate* state, Object name, Object attributes)
|
||||
{
|
||||
OCnode* attset;
|
||||
attset = newocnode((char*)name,OC_Attributeset,state);
|
||||
/* Check var set vs global set */
|
||||
attset->att.isglobal = isglobalname(name);
|
||||
attset->att.isdods = isdodsname(name);
|
||||
attset->subnodes = (OClist*)attributes;
|
||||
addedges(attset);
|
||||
return attset;
|
||||
}
|
||||
|
||||
static int
|
||||
isglobalname(const char* name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
int glen = strlen("global");
|
||||
const char* p;
|
||||
if(len < glen) return 0;
|
||||
p = name + (len - glen);
|
||||
if(strcasecmp(p,"global") != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
isdodsname(const char* name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
int glen = strlen("DODS");
|
||||
if(len < glen) return 0;
|
||||
if(ocstrncmp(name,"DODS",glen) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
isnumber(const char* text)
|
||||
{
|
||||
for(;*text;text++) {if(!isdigit(*text)) return 0;}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
dimension(OCnode* node, OClist* dimensions)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int rank = oclistlength(dimensions);
|
||||
node->array.dimensions = (OClist*)dimensions;
|
||||
node->array.rank = rank;
|
||||
for(i=0;i<rank;i++) {
|
||||
OCnode* dim = (OCnode*)oclistget(node->array.dimensions,i);
|
||||
dim->dim.array = node;
|
||||
dim->dim.arrayindex = i;
|
||||
#if 0
|
||||
if(dim->name == NULL) {
|
||||
dim->dim.anonymous = 1;
|
||||
dim->name = dimnameanon(node->name,i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
dimnameanon(char* basename, unsigned int index)
|
||||
{
|
||||
char name[64];
|
||||
sprintf(name,"%s_%d",basename,index);
|
||||
return strdup(name);
|
||||
}
|
||||
|
||||
Object
|
||||
dap_makebase(DAPparsestate* state, Object name, Object etype, Object dimensions)
|
||||
{
|
||||
OCnode* node;
|
||||
node = newocnode((char*)name,OC_Atomic,state);
|
||||
node->etype = octypefor(etype);
|
||||
dimension(node,(OClist*)dimensions);
|
||||
return node;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_makestructure(DAPparsestate* state, Object name, Object dimensions, Object fields)
|
||||
{
|
||||
OCnode* node;
|
||||
char* dupname;
|
||||
if((dupname=scopeduplicates((OClist*)fields))!= NULL) {
|
||||
dap_parse_error(state,"Duplicate structure field names in same scope: %s.%s",(char*)name,dupname);
|
||||
return (Object)NULL;
|
||||
}
|
||||
node = newocnode(name,OC_Structure,state);
|
||||
node->subnodes = fields;
|
||||
dimension(node,(OClist*)dimensions);
|
||||
addedges(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_makesequence(DAPparsestate* state, Object name, Object members)
|
||||
{
|
||||
OCnode* node;
|
||||
char* dupname;
|
||||
if((dupname=scopeduplicates((OClist*)members)) != NULL) {
|
||||
dap_parse_error(state,"Duplicate sequence member names in same scope: %s.%s",(char*)name,dupname);
|
||||
return (Object)NULL;
|
||||
}
|
||||
node = newocnode(name,OC_Sequence,state);
|
||||
node->subnodes = members;
|
||||
addedges(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Object
|
||||
dap_makegrid(DAPparsestate* state, Object name, Object arraydecl, Object mapdecls)
|
||||
{
|
||||
OCnode* node;
|
||||
/* Check for duplicate map names */
|
||||
char* dupname;
|
||||
if((dupname=scopeduplicates((OClist*)mapdecls)) != NULL) {
|
||||
dap_parse_error(state,"Duplicate grid map names in same scope: %s.%s",(char*)name,dupname);
|
||||
return (Object)NULL;
|
||||
}
|
||||
node = newocnode(name,OC_Grid,state);
|
||||
node->subnodes = (OClist*)mapdecls;
|
||||
oclistinsert(node->subnodes,0,(ocelem)arraydecl);
|
||||
addedges(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
addedges(OCnode* node)
|
||||
{
|
||||
unsigned int i;
|
||||
if(node->subnodes == NULL) return;
|
||||
for(i=0;i<oclistlength(node->subnodes);i++) {
|
||||
OCnode* subnode = (OCnode*)oclistget(node->subnodes,i);
|
||||
subnode->container = node;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setroot(OCnode* root, OClist* ocnodes)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<oclistlength(ocnodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(ocnodes,i);
|
||||
node->root = root;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
daperror(DAPparsestate* state, const char* msg)
|
||||
{
|
||||
dap_parse_error(state,msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char*
|
||||
flatten(char* s, char* tmp, int tlen)
|
||||
{
|
||||
int c;
|
||||
char* p,*q;
|
||||
strncpy(tmp,s,tlen);
|
||||
tmp[tlen] = '\0';
|
||||
p = (q = tmp);
|
||||
while((c=*p++)) {
|
||||
switch (c) {
|
||||
case '\r': case '\n': break;
|
||||
case '\t': *q++ = ' '; break;
|
||||
case ' ': if(*p != ' ') *q++ = c; break;
|
||||
default: *q++ = c;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Create an ocnode and capture in the state->ocnode list */
|
||||
static OCnode*
|
||||
newocnode(char* name, OCtype octype, DAPparsestate* state)
|
||||
{
|
||||
OCnode* node = ocnode_new(name,octype,state->root);
|
||||
oclistpush(state->ocnodes,(ocelem)node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static int
|
||||
check_int32(char* val, long* value)
|
||||
{
|
||||
char* ptr;
|
||||
int ok = 1;
|
||||
long iv = strtol(val,&ptr,0); /* 0=>auto determine base */
|
||||
if((iv == 0 && val == ptr) || *ptr != '\0') {ok=0; iv=1;}
|
||||
else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) ok=0;
|
||||
if(value != NULL) *value = iv;
|
||||
return ok;
|
||||
}
|
||||
|
||||
static char*
|
||||
scopeduplicates(OClist* list)
|
||||
{
|
||||
unsigned int i,j;
|
||||
for(i=0;i<oclistlength(list);i++) {
|
||||
OCnode* io = (OCnode*)oclistget(list,i);
|
||||
for(j=i+1;j<oclistlength(list);j++) {
|
||||
OCnode* jo = (OCnode*)oclistget(list,j);
|
||||
if(strcmp(io->name,jo->name)==0)
|
||||
return io->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static OCtype
|
||||
octypefor(Object etype)
|
||||
{
|
||||
switch ((long)etype) {
|
||||
case SCAN_BYTE: return OC_Byte;
|
||||
case SCAN_INT16: return OC_Int16;
|
||||
case SCAN_UINT16: return OC_UInt16;
|
||||
case SCAN_INT32: return OC_Int32;
|
||||
case SCAN_UINT32: return OC_UInt32;
|
||||
case SCAN_FLOAT32: return OC_Float32;
|
||||
case SCAN_FLOAT64: return OC_Float64;
|
||||
case SCAN_URL: return OC_URL;
|
||||
case SCAN_STRING: return OC_String;
|
||||
default: abort();
|
||||
}
|
||||
return OC_NAT;
|
||||
}
|
||||
|
||||
void
|
||||
dap_parse_error(DAPparsestate* state, const char *fmt, ...)
|
||||
{
|
||||
size_t len, suffixlen, prefixlen;
|
||||
va_list argv;
|
||||
char* tmp = NULL;
|
||||
va_start(argv,fmt);
|
||||
(void) vfprintf(stderr,fmt,argv) ;
|
||||
(void) fputc('\n',stderr) ;
|
||||
len = strlen(state->lexstate->input);
|
||||
suffixlen = strlen(state->lexstate->next);
|
||||
prefixlen = (len - suffixlen);
|
||||
tmp = (char*)ocmalloc(len+1);
|
||||
flatten(state->lexstate->input,tmp,prefixlen);
|
||||
(void) fprintf(stderr,"context: %s",tmp);
|
||||
flatten(state->lexstate->next,tmp,suffixlen);
|
||||
(void) fprintf(stderr,"^%s\n",tmp);
|
||||
(void) fflush(stderr); /* to ensure log files are current */
|
||||
ocfree(tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
dap_parse_cleanup(DAPparsestate* state)
|
||||
{
|
||||
daplexcleanup(&state->lexstate);
|
||||
if(state->ocnodes != NULL) ocnodes_free(state->ocnodes);
|
||||
state->ocnodes = NULL;
|
||||
free(state);
|
||||
}
|
||||
|
||||
static DAPparsestate*
|
||||
dap_parse_init(char* buf)
|
||||
{
|
||||
DAPparsestate* state = (DAPparsestate*)ocmalloc(sizeof(DAPparsestate)); /*ocmalloc zeros*/
|
||||
MEMCHECK(state,NULL);
|
||||
if(buf==NULL) {
|
||||
dap_parse_error(state,"dap_parse_init: no input buffer");
|
||||
dap_parse_cleanup(state);
|
||||
return NULL;
|
||||
}
|
||||
daplexinit(buf,&state->lexstate);
|
||||
return state;
|
||||
}
|
||||
|
||||
/* Wrapper for dapparse */
|
||||
OCerror
|
||||
DAPparse(OCstate* conn, OCtree* tree, char* parsestring)
|
||||
{
|
||||
DAPparsestate* state = dap_parse_init(parsestring);
|
||||
int parseresult;
|
||||
OCerror ocerr = OC_NOERR;
|
||||
state->ocnodes = oclistnew();
|
||||
state->conn = conn;
|
||||
if(ocdebug >= 2)
|
||||
dapdebug = 1;
|
||||
parseresult = dapparse(state);
|
||||
if(parseresult == 0) {/* 0 => parse ok */
|
||||
/* Check to see if we ended up parsing an error message */
|
||||
if(state->svcerror) {
|
||||
conn->error.code = nulldup(state->code);
|
||||
conn->error.message = nulldup(state->message);
|
||||
tree->root = NULL;
|
||||
/* Attempt to further decipher the error code */
|
||||
if(state->code != NULL
|
||||
&& (strcmp(state->code,"404") == 0 /* tds returns 404 */
|
||||
|| strcmp(state->code,"5") == 0)) /* hyrax returns 5 */
|
||||
ocerr = OC_ENOFILE;
|
||||
else
|
||||
ocerr = OC_EDAPSVC;
|
||||
} else {
|
||||
OCASSERT((state->root != NULL));
|
||||
tree->root = state->root;
|
||||
state->root = NULL; /* avoid reclaim */
|
||||
tree->nodes = state->ocnodes;
|
||||
state->ocnodes = NULL; /* avoid reclaim */
|
||||
tree->root->tree = tree;
|
||||
ocerr = OC_NOERR;
|
||||
}
|
||||
} else { /* Parse failed */
|
||||
switch (tree->dxdclass) {
|
||||
case OCDAS: ocerr = OC_EDAS; break;
|
||||
case OCDDS: ocerr = OC_EDDS; break;
|
||||
case OCDATADDS: ocerr = OC_EDATADDS; break;
|
||||
default: ocerr = OC_EDAPSVC;
|
||||
}
|
||||
}
|
||||
dap_parse_cleanup(state);
|
||||
return ocerr;
|
||||
}
|
||||
|
100
oc2/dapparselex.h
Normal file
100
oc2/dapparselex.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef DAPPARSELEX_H
|
||||
#define DAPPARSELEX_H 1
|
||||
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#ifdef USE_DAP
|
||||
/* To avoid "make distclean" wiping out dap.tab.h */
|
||||
#include "daptab.h"
|
||||
#else
|
||||
#include "daptab.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define strcasecmp stricmp
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/* For consistency with Java parser */
|
||||
#define null NULL
|
||||
|
||||
typedef void* Object;
|
||||
|
||||
#define YYSTYPE Object
|
||||
|
||||
#define MAX_TOKEN_LENGTH 1024
|
||||
|
||||
/*! Specifies the Lexstate. */
|
||||
typedef struct DAPlexstate {
|
||||
char* input;
|
||||
char* next; /* next char in uri.query*/
|
||||
OCbytes* yytext;
|
||||
int lineno;
|
||||
/*! Specifies the Lasttoken. */
|
||||
int lasttoken;
|
||||
char lasttokentext[MAX_TOKEN_LENGTH+1];
|
||||
char* wordchars1;
|
||||
char* wordcharsn;
|
||||
char* worddelims;
|
||||
OClist* reclaim; /* reclaim WORD_WORD instances */
|
||||
} DAPlexstate;
|
||||
|
||||
/*! Specifies the DAPparsestate. */
|
||||
typedef struct DAPparsestate {
|
||||
struct OCnode* root;
|
||||
DAPlexstate* lexstate;
|
||||
OClist* ocnodes;
|
||||
struct OCstate* conn;
|
||||
/* For error returns from the server */
|
||||
int svcerror; /* 1 => we had an error from the server */
|
||||
char* code;
|
||||
char* message;
|
||||
char* progtype;
|
||||
char* progname;
|
||||
/* State for constraint expressions */
|
||||
struct CEstate* cestate;
|
||||
} DAPparsestate;
|
||||
|
||||
extern int dapdebug; /* global state */
|
||||
|
||||
extern int daperror(DAPparsestate* state, const char* msg);
|
||||
extern void dap_parse_error(DAPparsestate*,const char *fmt, ...);
|
||||
/* bison parse entry point */
|
||||
extern int dapparse(DAPparsestate*);
|
||||
|
||||
extern Object dap_datasetbody(DAPparsestate*,Object decls, Object name);
|
||||
extern Object dap_declarations(DAPparsestate*,Object decls, Object decl);
|
||||
extern Object dap_arraydecls(DAPparsestate*,Object arraydecls, Object arraydecl);
|
||||
extern Object dap_arraydecl(DAPparsestate*,Object name, Object size);
|
||||
|
||||
extern void dap_dassetup(DAPparsestate*);
|
||||
extern Object dap_attributebody(DAPparsestate*,Object attrlist);
|
||||
extern Object dap_attrlist(DAPparsestate*,Object attrlist, Object attrtuple);
|
||||
extern Object dap_attribute(DAPparsestate*,Object name, Object value, Object etype);
|
||||
extern Object dap_attrset(DAPparsestate*,Object name, Object attributes);
|
||||
extern Object dap_attrvalue(DAPparsestate*,Object valuelist, Object value, Object etype);
|
||||
|
||||
extern Object dap_makebase(DAPparsestate*,Object name, Object etype, Object dimensions);
|
||||
extern Object dap_makestructure(DAPparsestate*,Object name, Object dimensions, Object fields);
|
||||
extern Object dap_makesequence(DAPparsestate*,Object name, Object members);
|
||||
extern Object dap_makegrid(DAPparsestate*,Object name, Object arraydecl, Object mapdecls);
|
||||
|
||||
extern void dap_errorbody(DAPparsestate*, Object, Object, Object, Object);
|
||||
extern void dap_unrecognizedresponse(DAPparsestate*);
|
||||
|
||||
extern void dap_tagparse(DAPparsestate*,int);
|
||||
|
||||
/* Lexer entry points */
|
||||
extern int daplex(YYSTYPE*, DAPparsestate*);
|
||||
extern void daplexinit(char* input, DAPlexstate** lexstatep);
|
||||
extern void daplexcleanup(DAPlexstate** lexstatep);
|
||||
extern void dapsetwordchars(DAPlexstate* lexstate, int kind);
|
||||
extern char* dapdecode(DAPlexstate*,char*);
|
||||
|
||||
extern OCerror DAPparse(OCstate*, struct OCtree*, char*);
|
||||
extern char* dimnameanon(char* basename, unsigned int index);
|
||||
|
||||
#endif /*DAPPARSELEX_H*/
|
2493
oc2/daptab.c
Normal file
2493
oc2/daptab.c
Normal file
File diff suppressed because it is too large
Load Diff
80
oc2/daptab.h
Normal file
80
oc2/daptab.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* A Bison parser, made by GNU Bison 2.4.3. */
|
||||
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||
2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
SCAN_ALIAS = 258,
|
||||
SCAN_ARRAY = 259,
|
||||
SCAN_ATTR = 260,
|
||||
SCAN_BYTE = 261,
|
||||
SCAN_CODE = 262,
|
||||
SCAN_DATASET = 263,
|
||||
SCAN_DATA = 264,
|
||||
SCAN_ERROR = 265,
|
||||
SCAN_FLOAT32 = 266,
|
||||
SCAN_FLOAT64 = 267,
|
||||
SCAN_GRID = 268,
|
||||
SCAN_INT16 = 269,
|
||||
SCAN_INT32 = 270,
|
||||
SCAN_MAPS = 271,
|
||||
SCAN_MESSAGE = 272,
|
||||
SCAN_SEQUENCE = 273,
|
||||
SCAN_STRING = 274,
|
||||
SCAN_STRUCTURE = 275,
|
||||
SCAN_UINT16 = 276,
|
||||
SCAN_UINT32 = 277,
|
||||
SCAN_URL = 278,
|
||||
SCAN_PTYPE = 279,
|
||||
SCAN_PROG = 280,
|
||||
WORD_WORD = 281,
|
||||
WORD_STRING = 282
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef int YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
16
oc2/dodsrc.example
Normal file
16
oc2/dodsrc.example
Normal file
@ -0,0 +1,16 @@
|
||||
CURL.VERBOSE=1
|
||||
#CURL.DEFLATE=0
|
||||
CURL.COOKIEJAR=.dods_cookies
|
||||
#CURL.COOKIEFILE=
|
||||
#CURL.CREDENTIALS.USER=
|
||||
#CURL.CREDENTIALS.PASSWORD=
|
||||
# SSL Support
|
||||
CURL.SSL.VALIDATE=1
|
||||
# For ESG access (e.g. http://ceda.ac.uk/...)
|
||||
# CURL.SSL.CERTIFICATE and CURL.SSL.KEY should have same value
|
||||
CURL.SSL.CERTIFICATE=/home/dmh/.globus/x509up_u13615
|
||||
CURL.SSL.KEY=/home/dmh/.globus/x509up_u13615
|
||||
#CURL.SSL.CAINFO=
|
||||
CURL.SSL.CAPATH=/home/dmh/.globus/certificates
|
||||
# Proxy configuration (optional parts in []s):
|
||||
#CURL.PROXY_SERVER=http://[username:password@]host[:port]
|
480
oc2/oc.h
Normal file
480
oc2/oc.h
Normal file
@ -0,0 +1,480 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT dap for more information. */
|
||||
|
||||
/*
|
||||
OC External Interface
|
||||
Created: 4/4/2009
|
||||
Last Revised: 6/7/2012
|
||||
Version: 2.0
|
||||
*/
|
||||
|
||||
#ifndef OC_H
|
||||
#define OC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*!\file oc.h
|
||||
*/
|
||||
|
||||
/*!\defgroup Definitions Constants, types, etc.
|
||||
@{*/
|
||||
|
||||
/*! OC_MAX_DIMS is the maximum allowable
|
||||
number of dimensions.
|
||||
Ideally, it should be greater or equal to max allowed by dap or netcdf
|
||||
*/
|
||||
#define OC_MAX_DIMENSIONS 1024
|
||||
|
||||
/*!\enum OCdxd
|
||||
Define the legal kinds of fetch: DAS, DDS, or DataDDS
|
||||
*/
|
||||
typedef enum OCdxd {
|
||||
OCDDS=0,
|
||||
OCDAS=1,
|
||||
OCDATADDS=2
|
||||
} OCdxd;
|
||||
|
||||
/*!\def OCDATA
|
||||
Define an alias for OCDATADDS
|
||||
*/
|
||||
#define OCDATA OCDATADDS
|
||||
|
||||
/*!
|
||||
\typedef OCflags
|
||||
Define flags for oc_fetch.
|
||||
*/
|
||||
typedef int OCflags;
|
||||
/*!\def OCONDISK
|
||||
Cause oc_fetch to store the retrieved data on disk.
|
||||
*/
|
||||
|
||||
#define OCONDISK 1
|
||||
/**************************************************/
|
||||
/* OCtype */
|
||||
|
||||
/*!\enum OCtype
|
||||
Define the set of legal types. The set is divided
|
||||
into two parts. The atomic types define
|
||||
leaf nodes of the DDS. The non-atomic types
|
||||
are used to tag internal nodes of the DDS tree.
|
||||
*/
|
||||
typedef enum OCtype {
|
||||
/* Atomic Types */
|
||||
/* OC_Ubyte, OC_Char, OC_Int64 and OC_UInt64 are defined for future extension*/
|
||||
OC_NAT=0,
|
||||
OC_Char=1,
|
||||
OC_Byte=2,
|
||||
OC_UByte=3,
|
||||
OC_Int16=4,
|
||||
OC_UInt16=5,
|
||||
OC_Int32=6,
|
||||
OC_UInt32=7,
|
||||
OC_Int64=8,
|
||||
OC_UInt64=9,
|
||||
OC_Float32=10,
|
||||
OC_Float64=11,
|
||||
OC_String=12,
|
||||
OC_URL=13,
|
||||
|
||||
/* Non-Atomic Types */
|
||||
OC_Atomic=100,
|
||||
OC_Dataset=101,
|
||||
OC_Sequence=102,
|
||||
OC_Grid=103,
|
||||
OC_Structure=104,
|
||||
OC_Dimension=105,
|
||||
OC_Attribute=106,
|
||||
OC_Attributeset=107,
|
||||
} OCtype;
|
||||
|
||||
/*!\enum OCerror
|
||||
Define the set of error return codes.
|
||||
The set consists of oc errors (negative
|
||||
values) plus the set of system errors, which
|
||||
are positive.
|
||||
*/
|
||||
typedef enum OCerror {
|
||||
OC_NOERR=0,
|
||||
OC_EBADID=-1,
|
||||
OC_ECHAR=-2,
|
||||
OC_EDIMSIZE=-3,
|
||||
OC_EEDGE=-4,
|
||||
OC_EINVAL=-5,
|
||||
OC_EINVALCOORDS=-6,
|
||||
OC_ENOMEM=-7,
|
||||
OC_ENOTVAR=-8,
|
||||
OC_EPERM=-9,
|
||||
OC_ESTRIDE=-10,
|
||||
OC_EDAP=-11,
|
||||
OC_EXDR=-12,
|
||||
OC_ECURL=-13,
|
||||
OC_EBADURL=-14,
|
||||
OC_EBADVAR=-15,
|
||||
OC_EOPEN=-16,
|
||||
OC_EIO=-17,
|
||||
OC_ENODATA=-18,
|
||||
OC_EDAPSVC=-19,
|
||||
OC_ENAMEINUSE=-20,
|
||||
OC_EDAS=-21,
|
||||
OC_EDDS=-22,
|
||||
OC_EDATADDS=-23,
|
||||
OC_ERCFILE=-24,
|
||||
OC_ENOFILE=-25,
|
||||
OC_EINDEX=-26,
|
||||
OC_EBADTYPE=-27,
|
||||
OC_ESCALAR=-28,
|
||||
} OCerror;
|
||||
|
||||
/*!\def OCLOGNOTE
|
||||
Tag a log entry as a note.
|
||||
*/
|
||||
#define OCLOGNOTE 0
|
||||
/*!\def OCLOGWARN
|
||||
Tag a log entry as a warning.
|
||||
*/
|
||||
#define OCLOGWARN 1
|
||||
/*!\def OCLOGERR
|
||||
Tag a log entry as an error.
|
||||
*/
|
||||
#define OCLOGERR 2
|
||||
/*!\def OCLOGDBG
|
||||
Tag a log entry as a debug note.
|
||||
*/
|
||||
#define OCLOGDBG 3
|
||||
|
||||
/**************************************************/
|
||||
/* Define the opaque types */
|
||||
|
||||
/*!\typedef OCobject
|
||||
Define a common opaque type.
|
||||
*/
|
||||
typedef void* OCobject;
|
||||
|
||||
/*!\typedef OCddsnode
|
||||
The OCddsnode type provide a reference
|
||||
to a component of a DAS or DDS tree:
|
||||
e.g. Sequence, Grid, Dataset, etc.
|
||||
These objects
|
||||
are nested, so most objects reference a container object
|
||||
and subnode objects. The term ddsnode is slightly misleading
|
||||
since it also covers DAS nodes.
|
||||
*/
|
||||
|
||||
typedef OCobject OCddsnode;
|
||||
|
||||
/*!\typedef OCdasnode
|
||||
The OCdasnode is a alias for OCddsnode.
|
||||
*/
|
||||
|
||||
typedef OCddsnode OCdasnode;
|
||||
|
||||
/* Data data type */
|
||||
/*!\typedef OCdatanode
|
||||
The OCdatanode type provide a reference
|
||||
to a specific piece of data in the data
|
||||
part of a Datadds.
|
||||
*/
|
||||
typedef OCobject OCdatanode;
|
||||
|
||||
/*!\typedef OClink
|
||||
Think of OClink as analogous to the C stdio FILE structure;
|
||||
it "holds" all the other state info about
|
||||
a connection to the server, the url request, and the DAS/DDS/DATADDSinfo.
|
||||
3/24/210: Renamed from OCconnection because of confusion about
|
||||
term "connection"
|
||||
*/
|
||||
typedef OCobject OClink;
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**************************************************/
|
||||
/* External API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************/
|
||||
/* Link management */
|
||||
|
||||
extern OCerror oc_open(const char* url, OClink*);
|
||||
extern OCerror oc_close(OClink);
|
||||
|
||||
/**************************************************/
|
||||
/* Tree Management */
|
||||
|
||||
extern OCerror oc_fetch(OClink,
|
||||
const char* constraints,
|
||||
OCdxd,
|
||||
OCflags,
|
||||
OCddsnode*);
|
||||
|
||||
extern OCerror oc_root_free(OClink, OCddsnode root);
|
||||
extern const char* oc_tree_text(OClink, OCddsnode root);
|
||||
|
||||
/**************************************************/
|
||||
/* Node Management */
|
||||
|
||||
extern OCerror oc_dds_properties(OClink, OCddsnode,
|
||||
char** namep,
|
||||
OCtype* typep,
|
||||
OCtype* atomictypep, /* if octype == OC_Atomic */
|
||||
OCddsnode* containerp, /* NULL if octype == OC_Dataset */
|
||||
size_t* rankp, /* 0 if scalar */
|
||||
size_t* nsubnodesp,
|
||||
size_t* nattrp);
|
||||
|
||||
/* Define some individual accessors for convenience */
|
||||
|
||||
extern OCerror oc_dds_name(OClink,OCddsnode,char**);
|
||||
extern OCerror oc_dds_class(OClink,OCddsnode,OCtype*);
|
||||
extern OCerror oc_dds_atomictype(OClink,OCddsnode,OCtype*);
|
||||
extern OCerror oc_dds_nsubnodes(OClink,OCddsnode,size_t*);
|
||||
extern OCerror oc_dds_rank(OClink,OCddsnode,size_t*);
|
||||
extern OCerror oc_dds_attr_count(OClink,OCddsnode,size_t*);
|
||||
extern OCerror oc_dds_root(OClink,OCddsnode,OCddsnode*);
|
||||
extern OCerror oc_dds_container(OClink,OCddsnode,OCddsnode*);
|
||||
|
||||
/* Aliases */
|
||||
#define oc_dds_octype oc_dds_class
|
||||
#define oc_dds_type oc_dds_class
|
||||
|
||||
/* Get the i'th field of the given (container) node; return OC_EINDEX
|
||||
if there is no such node; return OC_EBADTYPE if node is not
|
||||
a container
|
||||
*/
|
||||
extern OCerror oc_dds_ithfield(OClink, OCddsnode, size_t index, OCddsnode* dimids);
|
||||
|
||||
/* Alias for oc_dds_ithfield */
|
||||
extern OCerror oc_dds_ithsubnode(OClink, OCddsnode, size_t index, OCddsnode* dimids);
|
||||
|
||||
/* Return the dimension nodes, if any, associated with a given DDS node */
|
||||
/* Caller must allocate and free the vector for dimids */
|
||||
/* If the node is scalar, then return OC_ESCALAR. */
|
||||
extern OCerror oc_dds_dimensions(OClink, OCddsnode, OCddsnode* dimids);
|
||||
|
||||
/* Return the i'th dimension node, if any, associated with a given object */
|
||||
/* If there is no such dimension, then return OC_EINVAL */
|
||||
extern OCerror oc_dds_ithdimension(OClink,OCddsnode, size_t, OCddsnode*);
|
||||
|
||||
/* Return the size and name associated with a given dimension object
|
||||
as defined in the DDS
|
||||
*/
|
||||
extern OCerror oc_dimension_properties(OClink,OCddsnode,size_t*,char**);
|
||||
|
||||
/* For convenience, return only the dimension sizes */
|
||||
extern OCerror oc_dds_dimensionsizes(OClink,OCddsnode,size_t* dimsizes);
|
||||
|
||||
/* Attribute Management */
|
||||
|
||||
/* Obtain the attributes associated with a given DDS OCddsnode.
|
||||
One specifies the DDS root to get the global attributes
|
||||
The actual attribute strings are returned and the user
|
||||
must do any required conversion based on the octype.
|
||||
The strings vector must be allocated and freed by caller,
|
||||
The contents of the strings vector must also be reclaimed
|
||||
using oc_attr_reclaim(see below).
|
||||
Standard practice is to call twice, once with the strings
|
||||
argument == NULL so we get the number of values,
|
||||
then the second time with an allocated char** vector.
|
||||
|
||||
*/
|
||||
extern OCerror oc_dds_attr(OClink,OCddsnode, size_t i,
|
||||
char** name, OCtype* octype,
|
||||
size_t* nvalues, char** strings);
|
||||
|
||||
|
||||
/* Access ith value string of a DAS OC_Attribute object.
|
||||
OCddsnode of the object is assumed to be OC_Attribute.
|
||||
Note that this is different than the above oc_dds_attr
|
||||
that works on DDS nodes.
|
||||
Note also that the return value is always a string.
|
||||
Caller must free returned string.
|
||||
*/
|
||||
|
||||
extern OCerror oc_das_attr_count(OClink, OCddsnode, size_t* countp);
|
||||
|
||||
extern OCerror oc_das_attr(OClink,OCddsnode, size_t, OCtype*, char**);
|
||||
|
||||
/**************************************************/
|
||||
/* Free up a ddsnode that is no longer being used */
|
||||
extern OCerror oc_dds_free(OClink, OCddsnode);
|
||||
|
||||
/**************************************************/
|
||||
/* Data Procedures */
|
||||
|
||||
/* Get the root data of datadds */
|
||||
extern OCerror oc_data_getroot(OClink, OCddsnode treeroot, OCdatanode* rootp);
|
||||
|
||||
/* Return an data for the i'th field of the specified container data */
|
||||
extern OCerror oc_data_ithfield(OClink, OCdatanode container, size_t index,
|
||||
OCdatanode* fieldp);
|
||||
|
||||
/* Return the grid array data for the specified grid data */
|
||||
extern OCerror oc_data_gridarray(OClink, OCdatanode grid, OCdatanode* arrayp);
|
||||
|
||||
/* Return the i'th grid map data for the specified grid data.
|
||||
Map indices start at zero.
|
||||
*/
|
||||
extern OCerror oc_data_gridmap(OClink, OCdatanode grid, size_t index, OCdatanode* mapp);
|
||||
|
||||
/* Return the data of the container for the specified data.
|
||||
If it does not exist, then return OCNULL.
|
||||
*/
|
||||
extern OCerror oc_data_container(OClink, OCdatanode data, OCdatanode* containerp);
|
||||
|
||||
/* Return the data of the root for the specified data. */
|
||||
extern OCerror oc_data_root(OClink, OCdatanode data, OCdatanode* rootp);
|
||||
|
||||
/* Return the data of a dimensioned Structure corresponding
|
||||
to the element specified by the indices.
|
||||
*/
|
||||
extern OCerror oc_data_ithelement(OClink, OCdatanode data, size_t* indices, OCdatanode* elementp);
|
||||
|
||||
/* Return the i'th record data of a Sequence data. */
|
||||
extern OCerror oc_data_ithrecord(OClink, OCdatanode data, size_t index, OCdatanode* recordp);
|
||||
|
||||
/* Free up an data that is no longer being used */
|
||||
extern OCerror oc_data_free(OClink, OCdatanode data);
|
||||
|
||||
/* Count the records associated with a sequence */
|
||||
extern OCerror oc_data_recordcount(OClink, OCdatanode, size_t*);
|
||||
|
||||
/* Return the actual data values associated with the specified leaf data.
|
||||
The OCdatanode is assumed to be referencing a leaf node that is
|
||||
either a atomic valued scalar or array.
|
||||
If scalar, then index and count are ignored.
|
||||
Caller is responsible for allocating memory(of proper size)
|
||||
and free'ing it.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
extern OCerror oc_data_readscalar(OClink, OCdatanode, size_t, void*);
|
||||
|
||||
/* Like oc_data_read, but caller provides a starting set of indices
|
||||
and count of the number of elements to read.
|
||||
Caller is responsible for allocating memory(of proper size)
|
||||
and free'ing it.
|
||||
*/
|
||||
extern OCerror oc_data_readn(OClink, OCdatanode, size_t*, size_t, size_t, void*);
|
||||
|
||||
|
||||
/* Return the indices for this datas; Assumes the data
|
||||
was obtained using oc_data_ithelement or oc_data_ithrecord;
|
||||
if not, then an error is returned.
|
||||
*/
|
||||
extern OCerror oc_data_position(OClink, OCdatanode data, size_t* indices);
|
||||
|
||||
/* Return the template dds node for an data */
|
||||
extern OCerror oc_data_ddsnode(OClink, OCdatanode data, OCddsnode*);
|
||||
|
||||
/* Return the octype of the data (convenience) */
|
||||
extern OCerror oc_data_octype(OClink, OCdatanode data, OCtype*);
|
||||
|
||||
/* Return 1 if the specified data has a valid index, 0 otherwise.
|
||||
Valid index means it was created using
|
||||
oc_data_ithelement or oc_data_ithrecord.
|
||||
*/
|
||||
extern int oc_data_indexed(OClink link, OCdatanode datanode);
|
||||
|
||||
/* Return 1 if the specified data has a valid index, 0 otherwise.
|
||||
Valid index means it was created using
|
||||
oc_data_ithelement or oc_data_ithrecord.
|
||||
*/
|
||||
extern int oc_data_indexed(OClink, OCdatanode);
|
||||
|
||||
/* Return 1 if the specified data can be indexed
|
||||
Indexable means the data is pointing to
|
||||
an indexed structure or to a sequence.
|
||||
*/
|
||||
extern int oc_data_indexable(OClink, OCdatanode);
|
||||
|
||||
/**************************************************/
|
||||
/* Misc. OCtype-related functions */
|
||||
|
||||
/* Return size of the given type(Atomic only) */
|
||||
extern size_t oc_typesize(OCtype);
|
||||
|
||||
/* Return a canonical printable string describing a given type:
|
||||
e.g. Byte, Int16, etc.
|
||||
*/
|
||||
extern const char* oc_typetostring(OCtype);
|
||||
|
||||
/* Given a value of a atomic OC type, provide a canonical
|
||||
string representing that value; mostly for debugging.
|
||||
*/
|
||||
extern OCerror oc_typeprint(OCtype, void* value, size_t bufsize, char* buf);
|
||||
|
||||
/**************************************************/
|
||||
/* Logging */
|
||||
|
||||
extern void oc_loginit(void);
|
||||
extern int oc_setlogging(int onoff); /* 1=>start logging 0=>stop */
|
||||
extern int oc_logopen(const char* logfilename);
|
||||
extern void oc_logclose(void);
|
||||
|
||||
extern void oc_log(int tag, const char* fmt, ...);
|
||||
|
||||
extern void oc_logtext(int tag, const char* text);
|
||||
|
||||
/**************************************************/
|
||||
/* Miscellaneous */
|
||||
|
||||
/* Return the size of the in-memory or on-disk
|
||||
data chunk returned by the server for a given tree.
|
||||
Zero implies it is not defined.
|
||||
*/
|
||||
extern OCerror oc_raw_xdrsize(OClink,OCddsnode,off_t*);
|
||||
|
||||
/* Reclaim the strings within a string vector, but not the vector itself.
|
||||
This is useful for reclaiming the result of oc_data_read
|
||||
or oc_dds_attr when the type is OC_String or OC_URL.
|
||||
Note that only the strings are reclaimed, the string vector
|
||||
is not reclaimed because it was presumably allocated by the client.
|
||||
*/
|
||||
extern void oc_reclaim_strings(size_t n, char** svec);
|
||||
|
||||
/* Convert an OCerror to a human readable string */
|
||||
extern const char* oc_errstring(OCerror err);
|
||||
|
||||
/* Get client parameters from the URL
|
||||
DO NOT free the result
|
||||
*/
|
||||
extern const char* oc_clientparam_get(OClink, const char* param);
|
||||
|
||||
/* Test is a given url responds to a DAP protocol request */
|
||||
extern OCerror oc_ping(const char* url);
|
||||
|
||||
/**************************************************/
|
||||
/* Merging operations */
|
||||
|
||||
/* Merge a specified DAS into a specified DDS or DATADDS */
|
||||
extern OCerror oc_merge_das(OClink, OCddsnode dasroot, OCddsnode ddsroot);
|
||||
|
||||
/**************************************************/
|
||||
/* Debugging */
|
||||
|
||||
/* When a server error is detected, then it is possible
|
||||
to get the server error info using this procedure */
|
||||
extern OCerror oc_svcerrordata(OClink link, char** codep,
|
||||
char** msgp, long* httpp);
|
||||
|
||||
/**************************************************/
|
||||
/* Experimental */
|
||||
|
||||
/* Resend a url as a head request to check the Last-Modified time */
|
||||
extern OCerror oc_update_lastmodified_data(OClink);
|
||||
|
||||
/* Get last known modification time; -1 => data unknown */
|
||||
extern long oc_get_lastmodified_data(OClink);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*OC_H*/
|
190
oc2/ocbytes.c
Normal file
190
oc2/ocbytes.c
Normal file
@ -0,0 +1,190 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ocbytes.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define DEFAULTALLOC 1024
|
||||
#define ALLOCINCR 1024
|
||||
|
||||
static int ocbytesdebug = 1;
|
||||
|
||||
static long
|
||||
ocbytesfail(void)
|
||||
{
|
||||
fflush(stdout);
|
||||
fprintf(stderr,"bytebuffer failure\n");
|
||||
fflush(stderr);
|
||||
if(ocbytesdebug) abort();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
OCbytes*
|
||||
ocbytesnew(void)
|
||||
{
|
||||
OCbytes* bb = (OCbytes*)malloc(sizeof(OCbytes));
|
||||
if(bb == NULL) return (OCbytes*)ocbytesfail();
|
||||
bb->alloc=0;
|
||||
bb->length=0;
|
||||
bb->content=NULL;
|
||||
bb->nonextendible = 0;
|
||||
return bb;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytessetalloc(OCbytes* bb, unsigned int sz)
|
||||
{
|
||||
char* newcontent;
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
if(sz <= 0) {sz = (bb->alloc?2*bb->alloc:DEFAULTALLOC);}
|
||||
if(bb->alloc >= sz) return TRUE;
|
||||
if(bb->nonextendible) return ocbytesfail();
|
||||
newcontent=(char*)calloc(sz,sizeof(char));
|
||||
if(newcontent == NULL) return FALSE;
|
||||
if(bb->alloc > 0 && bb->length > 0 && bb->content != NULL) {
|
||||
memcpy((void*)newcontent,(void*)bb->content,sizeof(char)*bb->length);
|
||||
}
|
||||
if(bb->content != NULL) free(bb->content);
|
||||
bb->content=newcontent;
|
||||
bb->alloc=sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ocbytesfree(OCbytes* bb)
|
||||
{
|
||||
if(bb == NULL) return;
|
||||
if(!bb->nonextendible && bb->content != NULL) free(bb->content);
|
||||
free(bb);
|
||||
}
|
||||
|
||||
int
|
||||
ocbytessetlength(OCbytes* bb, unsigned int sz)
|
||||
{
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
if(sz > bb->alloc) {if(!ocbytessetalloc(bb,sz)) return ocbytesfail();}
|
||||
bb->length = sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesfill(OCbytes* bb, char fill)
|
||||
{
|
||||
unsigned int i;
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
for(i=0;i<bb->length;i++) bb->content[i] = fill;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesget(OCbytes* bb, unsigned int index)
|
||||
{
|
||||
if(bb == NULL) return -1;
|
||||
if(index >= bb->length) return -1;
|
||||
return bb->content[index];
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesset(OCbytes* bb, unsigned int index, char elem)
|
||||
{
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
if(index >= bb->length) return ocbytesfail();
|
||||
bb->content[index] = elem;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesappend(OCbytes* bb, char elem)
|
||||
{
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
/* We need space for the char + null */
|
||||
while(bb->length+1 >= bb->alloc) {
|
||||
if(!ocbytessetalloc(bb,0)) return ocbytesfail();
|
||||
}
|
||||
bb->content[bb->length] = elem;
|
||||
bb->length++;
|
||||
bb->content[bb->length] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This assumes s is a null terminated string*/
|
||||
int
|
||||
ocbytescat(OCbytes* bb, const char* s)
|
||||
{
|
||||
ocbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
|
||||
/* back up over the trailing null*/
|
||||
if(bb->length == 0) return ocbytesfail();
|
||||
bb->length--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesappendn(OCbytes* bb, const void* elem, unsigned int n)
|
||||
{
|
||||
if(bb == NULL || elem == NULL) return ocbytesfail();
|
||||
if(n == 0) {n = strlen((char*)elem);}
|
||||
while(!ocbytesavail(bb,n+1)) {
|
||||
if(!ocbytessetalloc(bb,0)) return ocbytesfail();
|
||||
}
|
||||
memcpy((void*)&bb->content[bb->length],(void*)elem,n);
|
||||
bb->length += n;
|
||||
bb->content[bb->length] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytesprepend(OCbytes* bb, const char elem)
|
||||
{
|
||||
int i; /* do not make unsigned */
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
if(bb->length >= bb->alloc) if(!ocbytessetalloc(bb,0)) return ocbytesfail();
|
||||
/* could we trust memcpy? instead */
|
||||
for(i=bb->alloc;i>=1;i--) {bb->content[i]=bb->content[i-1];}
|
||||
bb->content[0] = elem;
|
||||
bb->length++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char*
|
||||
ocbytesdup(OCbytes* bb)
|
||||
{
|
||||
char* result = (char*)malloc(bb->length+1);
|
||||
memcpy((void*)result,(const void*)bb->content,bb->length);
|
||||
result[bb->length] = '\0'; /* just in case it is a string*/
|
||||
return result;
|
||||
}
|
||||
|
||||
char*
|
||||
ocbytesextract(OCbytes* bb)
|
||||
{
|
||||
char* result = bb->content;
|
||||
bb->alloc = 0;
|
||||
bb->length = 0;
|
||||
bb->content = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
ocbytessetcontents(OCbytes* bb, char* contents, unsigned int alloc)
|
||||
{
|
||||
if(bb == NULL) return ocbytesfail();
|
||||
ocbytesclear(bb);
|
||||
if(!bb->nonextendible && bb->content != NULL) free(bb->content);
|
||||
bb->content = contents;
|
||||
bb->length = 0;
|
||||
bb->alloc = alloc;
|
||||
bb->nonextendible = 1;
|
||||
return 1;
|
||||
}
|
54
oc2/ocbytes.h
Normal file
54
oc2/ocbytes.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCBYTES_H
|
||||
#define OCBYTES_H 1
|
||||
|
||||
typedef struct OCbytes {
|
||||
int nonextendible; /* 1 => fail if an attempt is made to extend this buffer*/
|
||||
unsigned int alloc;
|
||||
unsigned int length;
|
||||
char* content;
|
||||
} OCbytes;
|
||||
|
||||
#if defined(_CPLUSPLUS_) || defined(__CPLUSPLUS__) || defined(__CPLUSPLUS)
|
||||
#define EXTERNC extern "C"
|
||||
#else
|
||||
#define EXTERNC extern
|
||||
#endif
|
||||
|
||||
EXTERNC OCbytes* ocbytesnew(void);
|
||||
EXTERNC void ocbytesfree(OCbytes*);
|
||||
EXTERNC int ocbytessetalloc(OCbytes*,unsigned int);
|
||||
EXTERNC int ocbytessetlength(OCbytes*,unsigned int);
|
||||
EXTERNC int ocbytesfill(OCbytes*, char fill);
|
||||
|
||||
/* Produce a duplicate of the contents*/
|
||||
EXTERNC char* ocbytesdup(OCbytes*);
|
||||
/* Extract the contents and leave buffer empty */
|
||||
EXTERNC char* ocbytesextract(OCbytes*);
|
||||
|
||||
/* Return the ith byte; -1 if no such index */
|
||||
EXTERNC int ocbytesget(OCbytes*,unsigned int);
|
||||
/* Set the ith byte */
|
||||
EXTERNC int ocbytesset(OCbytes*,unsigned int,char);
|
||||
|
||||
/* Append one byte */
|
||||
EXTERNC int ocbytesappend(OCbytes*,const char); /* Add at Tail */
|
||||
/* Append n bytes */
|
||||
EXTERNC int ocbytesappendn(OCbytes*,const void*,unsigned int); /* Add at Tail */
|
||||
|
||||
/* Concatenate a null-terminated string to the end of the buffer */
|
||||
EXTERNC int ocbytescat(OCbytes*,const char*);
|
||||
/* Set the contents of the buffer; mark the buffer as non-extendible */
|
||||
EXTERNC int ocbytessetcontents(OCbytes*, char*, unsigned int);
|
||||
|
||||
/* Following are always "in-lined"*/
|
||||
#define ocbyteslength(bb) ((bb)?(bb)->length:0U)
|
||||
#define ocbytesalloc(bb) ((bb)?(bb)->alloc:0U)
|
||||
#define ocbytescontents(bb) ((bb && bb->content)?(bb)->content:(char*)"")
|
||||
#define ocbytesextend(bb,len) ocbytessetalloc((bb),(len)+(bb->alloc))
|
||||
#define ocbytesclear(bb) ((bb)?(bb)->length=0:0U)
|
||||
#define ocbytesavail(bb,n) ((bb)?((bb)->alloc - (bb)->length) >= (n):0U)
|
||||
|
||||
#endif /*OCBYTES_H*/
|
128
oc2/occlientparams.c
Normal file
128
oc2/occlientparams.c
Normal file
@ -0,0 +1,128 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
|
||||
#define LBRACKET '['
|
||||
#define RBRACKET ']'
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Client parameters are assumed to be
|
||||
one or more instances of bracketed pairs:
|
||||
e.g "[...][...]...".
|
||||
The bracket content in turn is assumed to be a
|
||||
comma separated list of <name>=<value> pairs.
|
||||
e.g. x=y,z=,a=b.
|
||||
If the same parameter is specifed more than once,
|
||||
then the first occurrence is used; this is so that
|
||||
is possible to forcibly override user specified
|
||||
parameters by prefixing.
|
||||
IMPORTANT: client parameter string is assumed to
|
||||
have blanks compress out.
|
||||
*/
|
||||
|
||||
int
|
||||
ocparamdecode(OCstate* state)
|
||||
{
|
||||
int i;
|
||||
i = ocuridecodeparams(state->uri);
|
||||
return i?OC_NOERR:OC_EBADURL;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
ocparamlookup(OCstate* state, const char* key)
|
||||
{
|
||||
if(state == NULL || key == NULL || state->uri == NULL) return NULL;
|
||||
return ocurilookup(state->uri,key);
|
||||
}
|
||||
|
||||
int
|
||||
ocparamset(OCstate* state, const char* params)
|
||||
{
|
||||
int i;
|
||||
i = ocurisetparams(state->uri,params);
|
||||
return i?OC_NOERR:OC_EBADURL;
|
||||
}
|
||||
|
||||
#ifdef OCIGNORE
|
||||
void
|
||||
ocparamfree(OClist* params)
|
||||
{
|
||||
int i;
|
||||
if(params == NULL) return;
|
||||
for(i=0;i<oclistlength(params);i++) {
|
||||
char* s = (char*)oclistget(params,i);
|
||||
if(s != NULL) free((void*)s);
|
||||
}
|
||||
oclistfree(params);
|
||||
}
|
||||
|
||||
/*
|
||||
Delete the entry.
|
||||
return value = 1 => found and deleted;
|
||||
0 => param not found
|
||||
*/
|
||||
int
|
||||
ocparamdelete(OClist* params, const char* clientparam)
|
||||
{
|
||||
int i,found = 0;
|
||||
if(params == NULL || clientparam == NULL) return 0;
|
||||
for(i=0;i<oclistlength(params);i+=2) {
|
||||
char* name = (char*)oclistget(params,i);
|
||||
if(strcmp(clientparam,name)==0) {found=1; break;}
|
||||
}
|
||||
if(found) {
|
||||
oclistremove(params,i+1); /* remove value */
|
||||
oclistremove(params,i); /* remove name */
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Insert new client param (name,value);
|
||||
return value = 1 => not already defined
|
||||
0 => param already defined (no change)
|
||||
*/
|
||||
int
|
||||
ocparaminsert(OClist* params, const char* clientparam, const char* value)
|
||||
{
|
||||
int i;
|
||||
if(params == NULL || clientparam == NULL) return 0;
|
||||
for(i=0;i<oclistlength(params);i+=2) {
|
||||
char* name = (char*)oclistget(params,i);
|
||||
if(strcmp(clientparam,name)==0) return 0;
|
||||
}
|
||||
/* not found, append */
|
||||
oclistpush(params,(ocelem)nulldup(clientparam));
|
||||
oclistpush(params,(ocelem)nulldup(value));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Replace new client param (name,value);
|
||||
return value = 1 => replacement performed
|
||||
0 => insertion performed
|
||||
*/
|
||||
int
|
||||
ocparamreplace(OClist* params, const char* clientparam, const char* value)
|
||||
{
|
||||
int i;
|
||||
if(params == NULL || clientparam == NULL) return 0;
|
||||
for(i=0;i<oclistlength(params);i+=2) {
|
||||
char* name = (char*)oclistget(params,i);
|
||||
if(strcmp(clientparam,name)==0) {
|
||||
oclistinsert(params,i+1,(ocelem)nulldup(value));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
ocparaminsert(params,clientparam,value);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
11
oc2/occlientparams.h
Normal file
11
oc2/occlientparams.h
Normal file
@ -0,0 +1,11 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCCLIENTPARAMS_H
|
||||
#define OCCLIENTPARAMS_H
|
||||
|
||||
extern OClist* ocparamdecode(OCstate*);
|
||||
extern const char* ocparamlookup(OCstate*, const char*);
|
||||
extern void ocparamset(OCstate*,const char*);
|
||||
|
||||
#endif /*OCCLIENTPARAMS_H*/
|
414
oc2/occompile.c
Normal file
414
oc2/occompile.c
Normal file
@ -0,0 +1,414 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "ocdump.h"
|
||||
|
||||
/* 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 occompileatomic(OCstate*, OCdata*, XXDR*);
|
||||
static int ocerrorstring(XXDR* xdrs);
|
||||
|
||||
/* Sequence tag constant */
|
||||
const char StartOfSequence = '\x5A';
|
||||
const char EndOfSequence = '\xA5';
|
||||
|
||||
/*
|
||||
Provide an option that makes a single pass over
|
||||
the data packet and record pointers into it
|
||||
to speed up access.
|
||||
*/
|
||||
|
||||
/* Assume we are operating on the datadds tree */
|
||||
OCerror
|
||||
occompile(OCstate* state, OCnode* xroot)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
XXDR* xxdrs;
|
||||
OCtree* xtree;
|
||||
OCdata* data;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(xroot != NULL);
|
||||
OCASSERT(xroot->tree != NULL);
|
||||
OCASSERT(xroot->tree->dxdclass == OCDATADDS);
|
||||
OCASSERT(xroot->tree->data.data == NULL);
|
||||
|
||||
xtree = xroot->tree;
|
||||
|
||||
xxdrs = xtree->data.xdrs;
|
||||
if(xxdrs == NULL) return OCTHROW(OC_EXDR);
|
||||
|
||||
ocstat = occompile1(state,xroot,xxdrs,&data);
|
||||
if(ocstat == OC_NOERR)
|
||||
xtree->data.data = data;
|
||||
|
||||
#ifdef OCDEBUG
|
||||
{
|
||||
OCbytes* buffer = ocbytesnew();
|
||||
ocdumpdatatree(state,data,buffer,0);
|
||||
fprintf(stderr,"datatree:\n%s",ocbytescontents(buffer));
|
||||
ocbytesfree(buffer);
|
||||
}
|
||||
#endif
|
||||
return OCTHROW(ocstat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
occompile1(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** datap)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
int i;
|
||||
OCdata* data = NULL;
|
||||
size_t nelements = 0;
|
||||
OClist* records = NULL;
|
||||
|
||||
/* Allocate instance for this node */
|
||||
data = newocdata(xnode);
|
||||
MEMFAIL(data);
|
||||
|
||||
/* Capture position(s) */
|
||||
data->xdroffset = xxdr_getpos(xxdrs);
|
||||
|
||||
switch (xnode->octype) {
|
||||
|
||||
case OC_Dataset:
|
||||
case OC_Grid: /* Always scalars */
|
||||
ocstat = occompilefields(state,data,xxdrs);
|
||||
if(ocstat != OC_NOERR) goto fail;
|
||||
break;
|
||||
|
||||
case OC_Structure:
|
||||
if(xnode->array.rank == 0) {/* scalar */
|
||||
ocstat = occompilefields(state,data,xxdrs);
|
||||
if(ocstat != OC_NOERR) goto fail;
|
||||
} else { /* dimensioned structure */
|
||||
unsigned int xdrcount;
|
||||
fset(data->datamode,OCDT_ARRAY);
|
||||
/* Determine # of instances */
|
||||
nelements = octotaldimsize(xnode->array.rank,xnode->array.sizes);
|
||||
if(nelements == 0) return OCTHROW(OC_ENODATA);
|
||||
/* Validate and skip the leading count field */
|
||||
if(!xxdr_uint(xxdrs,&xdrcount))
|
||||
{ocstat = OC_EXDR; goto fail;}
|
||||
if(xdrcount != nelements)
|
||||
{ocstat=OC_EINVALCOORDS; goto fail;}
|
||||
|
||||
/* allocate space to capture all the element instances */
|
||||
data->instances = (OCdata**)malloc(nelements*sizeof(OCdata*));
|
||||
MEMFAIL(data);
|
||||
data->ninstances = 0;
|
||||
|
||||
/* create and fill the element instances */
|
||||
for(i=0;i<nelements;i++) {
|
||||
OCdata* instance = newocdata(xnode);
|
||||
MEMFAIL(instance);
|
||||
fset(instance->datamode,OCDT_ELEMENT);
|
||||
data->instances[i] = instance;
|
||||
data->ninstances++;
|
||||
/* Capture the back link */
|
||||
instance->container = data;
|
||||
instance->index = i;
|
||||
/* capture the current instance position */
|
||||
instance->xdroffset = xxdr_getpos(xxdrs);
|
||||
/* Now compile the fields of this instance */
|
||||
ocstat = occompilefields(state,instance,xxdrs);
|
||||
if(ocstat != OC_NOERR) {goto fail;}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OC_Sequence:
|
||||
/* Since we do not know the # records beforehand,
|
||||
use a oclist to collect the record instances.
|
||||
*/
|
||||
fset(data->datamode,OCDT_SEQUENCE);
|
||||
records = oclistnew();
|
||||
for(nelements=0;;nelements++) {
|
||||
/* pick up the sequence record begin marker*/
|
||||
char tmp[sizeof(unsigned int)];
|
||||
/* extract the tag byte*/
|
||||
if(!xxdr_opaque(xxdrs,tmp,sizeof(tmp)))
|
||||
{ocstat = OC_EXDR; goto fail;}
|
||||
if(tmp[0] == StartOfSequence) {
|
||||
/* Allocate a record instance */
|
||||
OCdata* record;
|
||||
ocstat = occompilerecord(state,xnode,xxdrs,&record);
|
||||
if(ocstat != OC_NOERR) goto fail;
|
||||
/* Capture the back link */
|
||||
record->container = data;
|
||||
record->index = nelements;
|
||||
oclistpush(records,(ocelem)record);
|
||||
record = NULL;
|
||||
} else if(tmp[0] == EndOfSequence) {
|
||||
break; /* we are done with the this sequence instance*/
|
||||
} else {
|
||||
oc_log(LOGERR,"missing/invalid begin/end record marker\n");
|
||||
ocstat = OC_EINVALCOORDS;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
OCASSERT(nelements == oclistlength(records));
|
||||
/* extract the content */
|
||||
data->ninstances = nelements;
|
||||
data->instances = (OCdata**)oclistdup(records);
|
||||
MEMFAIL(data);
|
||||
oclistfree(records);
|
||||
records = NULL;
|
||||
break;
|
||||
|
||||
case OC_Atomic:
|
||||
fset(data->datamode,OCDT_ATOMIC);
|
||||
ocstat = occompileatomic(state,data,xxdrs);
|
||||
if(ocstat != OC_NOERR) goto fail;
|
||||
break;
|
||||
|
||||
default:
|
||||
OCPANIC1("occompile: encountered unexpected node type: %x",xnode->octype);
|
||||
break;
|
||||
}
|
||||
|
||||
/*ok:*/
|
||||
if(datap) *datap = data;
|
||||
return OCTHROW(ocstat);
|
||||
|
||||
fail:
|
||||
/* See if we can extract error info from the response */
|
||||
ocerrorstring(xxdrs);
|
||||
|
||||
if(records != NULL) {
|
||||
for(i=0;i<oclistlength(records);i++)
|
||||
ocdata_free(state,(OCdata*)oclistget(records,i));
|
||||
}
|
||||
if(data != NULL && data->instances != NULL) {
|
||||
for(i=0;i<data->ninstances;i++)
|
||||
ocdata_free(state,data->instances[i]);
|
||||
}
|
||||
return OCTHROW(ocstat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
occompilerecord(OCstate* state, OCnode* xnode, XXDR* xxdrs, OCdata** recordp)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
OCdata* record = newocdata(xnode);/* create record record */
|
||||
MEMFAIL(record);
|
||||
fset(record->datamode,OCDT_RECORD);
|
||||
record->template = xnode;
|
||||
/* capture the current record position */
|
||||
record->xdroffset = xxdr_getpos(xxdrs);
|
||||
/* Compile the fields of this record */
|
||||
ocstat = OCTHROW(occompilefields(state,record,xxdrs));
|
||||
if(ocstat == OC_NOERR) {
|
||||
if(recordp) *recordp = record;
|
||||
}
|
||||
return OCTHROW(ocstat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
occompilefields(OCstate* state, OCdata* data, XXDR* xxdrs)
|
||||
{
|
||||
int i;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
size_t nelements;
|
||||
OCnode* xnode = data->template;
|
||||
|
||||
nelements = oclistlength(xnode->subnodes);
|
||||
if(nelements == 0)
|
||||
goto done;
|
||||
data->instances = (OCdata**)malloc(nelements*sizeof(OCdata*));
|
||||
MEMFAIL(data->instances);
|
||||
for(i=0;i<nelements;i++) {
|
||||
OCnode* fieldnode;
|
||||
OCdata* fieldinstance;
|
||||
fieldnode = (OCnode*)oclistget(xnode->subnodes,i);
|
||||
ocstat = occompile1(state,fieldnode,xxdrs,&fieldinstance);
|
||||
if(ocstat != OC_NOERR)
|
||||
goto fail;
|
||||
fset(fieldinstance->datamode,OCDT_FIELD);
|
||||
data->instances[i] = fieldinstance;
|
||||
data->ninstances++;
|
||||
/* Capture the back link */
|
||||
fieldinstance->container = data;
|
||||
fieldinstance->index = i;
|
||||
}
|
||||
|
||||
done:
|
||||
return OCTHROW(ocstat);
|
||||
|
||||
fail:
|
||||
if(data != NULL && data->instances != NULL) {
|
||||
for(i=0;i<data->ninstances;i++)
|
||||
ocdata_free(state,data->instances[i]);
|
||||
}
|
||||
return OCTHROW(ocstat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
occompileatomic(OCstate* state, OCdata* data, XXDR* xxdrs)
|
||||
{
|
||||
OCerror ocstat = OC_NOERR;
|
||||
int i;
|
||||
size_t nelements,xdrsize;
|
||||
unsigned int xxdrcount;
|
||||
OCnode* xnode = data->template;
|
||||
int scalar = (xnode->array.rank == 0);
|
||||
|
||||
OCASSERT((xnode->octype == OC_Atomic));
|
||||
|
||||
if(!scalar) {
|
||||
/* Use the count from the datadds */
|
||||
nelements = octotaldimsize(xnode->array.rank,xnode->array.sizes);
|
||||
/* Get first copy of the dimension count */
|
||||
if(!xxdr_uint(xxdrs,&xxdrcount)) {ocstat = OC_EXDR; goto fail;}
|
||||
if(xxdrcount != nelements) {ocstat=OC_EINVALCOORDS; goto fail;}
|
||||
if(xnode->etype != OC_String && xnode->etype != OC_URL) {
|
||||
/* Get second copy of the dimension count */
|
||||
if(!xxdr_uint(xxdrs,&xxdrcount)) {ocstat = OC_EXDR; goto fail;}
|
||||
if(xxdrcount != nelements) {ocstat=OC_EINVALCOORDS; goto fail;}
|
||||
}
|
||||
} else { /*scalar*/
|
||||
nelements = 1;
|
||||
xxdrcount = 1;
|
||||
}
|
||||
|
||||
data->xdroffset = xxdr_getpos(xxdrs);
|
||||
data->ninstances = xxdrcount;
|
||||
data->xdrsize = ocxdrsize(xnode->etype,scalar);
|
||||
|
||||
switch (xnode->etype) {
|
||||
|
||||
/* Do the fixed sized, non-packed cases */
|
||||
case OC_Int16: case OC_UInt16:
|
||||
case OC_Int32: case OC_UInt32:
|
||||
case OC_Int64: case OC_UInt64:
|
||||
case OC_Float32: case OC_Float64:
|
||||
/* Skip the data */
|
||||
xxdr_skip(xxdrs,data->ninstances*data->xdrsize);
|
||||
break;
|
||||
|
||||
/* Do the fixed sized, possibly packed cases */
|
||||
case OC_Byte:
|
||||
case OC_UByte:
|
||||
case OC_Char:
|
||||
/* Get the totalsize and round up to multiple of XDRUNIT */
|
||||
xdrsize = data->ninstances*data->xdrsize;
|
||||
xdrsize = RNDUP(xdrsize);
|
||||
/* Skip the data */
|
||||
xxdr_skip(xxdrs,xdrsize);
|
||||
break;
|
||||
|
||||
/* Hard case, because strings are variable length */
|
||||
case OC_String: case OC_URL:
|
||||
/* Start by allocating a set of pointers for each string */
|
||||
data->nstrings = xxdrcount;
|
||||
data->strings = (off_t*)malloc(sizeof(off_t)*data->nstrings);
|
||||
/* We need to walk each string, get size, then skip */
|
||||
for(i=0;i<data->nstrings;i++) {
|
||||
unsigned int len;
|
||||
data->strings[i] = xxdr_getpos(xxdrs);
|
||||
/* get exact string length */
|
||||
if(!xxdr_uint(xxdrs,&len)) {ocstat = OC_EXDR; goto fail;}
|
||||
len = RNDUP(len);
|
||||
/* Skip the data */
|
||||
xxdr_skip(xxdrs,len);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
OCPANIC1("unexpected etype: %d",xnode->etype);
|
||||
|
||||
} /* switch */
|
||||
|
||||
/*ok:*/
|
||||
return OCTHROW(ocstat);
|
||||
|
||||
fail:
|
||||
if(data->strings != NULL)
|
||||
free(data->strings);
|
||||
data->strings = NULL;
|
||||
data->ninstances = 0;
|
||||
return OCTHROW(ocstat);
|
||||
}
|
||||
|
||||
void
|
||||
ocdata_free(OCstate* state, OCdata* data)
|
||||
{
|
||||
if(data == NULL)
|
||||
return;
|
||||
|
||||
if(data->instances != NULL) {
|
||||
int i;
|
||||
for(i=0;i<data->ninstances;i++)
|
||||
ocdata_free(state,data->instances[i]);
|
||||
free(data->instances);
|
||||
}
|
||||
if(data->strings != NULL)
|
||||
free(data->strings);
|
||||
}
|
||||
|
||||
static OCdata*
|
||||
newocdata(OCnode* template)
|
||||
{
|
||||
OCdata* data = (OCdata*)calloc(1,sizeof(OCdata));
|
||||
MEMCHECK(data,NULL);
|
||||
data->header.magic = OCMAGIC;
|
||||
data->header.occlass = OC_Data;
|
||||
data->template = template;
|
||||
return data;
|
||||
}
|
||||
|
||||
/* XDR representation size depends on if this is scalar or not */
|
||||
static size_t
|
||||
ocxdrsize(OCtype etype, int isscalar)
|
||||
{
|
||||
switch (etype) {
|
||||
case OC_Char:
|
||||
case OC_Byte:
|
||||
case OC_UByte:
|
||||
return (isscalar? XDRUNIT : 1);
|
||||
case OC_Int16:
|
||||
case OC_UInt16:
|
||||
case OC_Int32:
|
||||
case OC_UInt32:
|
||||
case OC_Float32:
|
||||
return XDRUNIT;
|
||||
case OC_Float64:
|
||||
case OC_Int64:
|
||||
case OC_UInt64:
|
||||
return 2*XDRUNIT;
|
||||
default:
|
||||
break; /* no simple size */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define tag "Error {\n"
|
||||
|
||||
static int
|
||||
ocerrorstring(XXDR* xdrs)
|
||||
{
|
||||
/* Check to see if the xdrs contains "Error {\n'; assume it is at the beginning of data */
|
||||
off_t avail = xxdr_getavail(xdrs);
|
||||
char* data = (char*)malloc(avail);
|
||||
if(!xxdr_setpos(xdrs,0)) return 0;
|
||||
if(!xxdr_opaque(xdrs,data,avail)) return 0;
|
||||
/* check for error tag at front */
|
||||
if(ocstrncmp(data,tag,sizeof(tag))==0) {
|
||||
char* p;
|
||||
if((p=strchr(data,'}')) != NULL) *(++p)='\0';
|
||||
oc_log(LOGERR,"Server error: %s",data);
|
||||
/* Since important, report to stderr as well */
|
||||
fprintf(stderr,"Server error: %s",data);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
9
oc2/occompile.h
Normal file
9
oc2/occompile.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCCOMPILE_H
|
||||
#define OCCOMPILE_H
|
||||
|
||||
extern OCerror occompile(OCstate* state, OCnode* xroot);
|
||||
|
||||
#endif /*OCCOMPILE_H*/
|
39
oc2/occonstraints.h
Normal file
39
oc2/occonstraints.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef CONSTRAINTS_H
|
||||
#define CONSTRAINTS_H 1
|
||||
|
||||
/*! Specifies an OCslice. */
|
||||
typedef struct OCslice {
|
||||
size_t first;
|
||||
size_t count;
|
||||
size_t stride;
|
||||
size_t stop; /* == first + count */
|
||||
size_t declsize; /* from defining dimension, if any.*/
|
||||
} OCslice;
|
||||
|
||||
/*! Specifies a form of path where each element can have a set of associated indices */
|
||||
typedef struct OCpath {
|
||||
OClist* names;
|
||||
OClist* indexsets; /* oclist<oclist<Slice>> */
|
||||
} OCpath;
|
||||
|
||||
/*! Specifies a ProjectionClause. */
|
||||
typedef struct OCprojectionclause {
|
||||
char* target; /* "variable name" as mentioned in the projection */
|
||||
OClist* indexsets; /* oclist<oclist<OCslice>> */
|
||||
struct OCnode* node; /* node with name matching target, if any. */
|
||||
int gridconstraint; /* used only for testing purposes */
|
||||
} OCprojectionclause;
|
||||
|
||||
/*! Selection is the node type for selection expression trees */
|
||||
typedef struct OCselectionclause {
|
||||
int op;
|
||||
char* value;
|
||||
struct OCselectionclause* lhs;
|
||||
OClist* rhs;
|
||||
} OCselectionclause;
|
||||
|
||||
|
||||
#endif /*CONSTRAINTS_H*/
|
236
oc2/occurlfunctions.c
Normal file
236
oc2/occurlfunctions.c
Normal file
@ -0,0 +1,236 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "ocrc.h"
|
||||
|
||||
/* Condition on libcurl version */
|
||||
/* Set up an alias as needed */
|
||||
#ifndef HAVE_CURLOPT_KEYPASSWD
|
||||
#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD
|
||||
#endif
|
||||
|
||||
|
||||
static char* combinecredentials(const char* user, const char* pwd);
|
||||
|
||||
void
|
||||
oc_curl_debug(OCstate* state)
|
||||
{
|
||||
curl_easy_setopt(state->curl,CURLOPT_VERBOSE,1);
|
||||
curl_easy_setopt(state->curl,CURLOPT_ERRORBUFFER,(void*)state->curlerror);
|
||||
}
|
||||
|
||||
void
|
||||
oc_curl_printerror(OCstate* state)
|
||||
{
|
||||
fprintf(stderr,"curl error details: %s\n",state->curlerror);
|
||||
}
|
||||
|
||||
/* Determine if this version of curl supports
|
||||
"file://..." &/or "https://..." urls.
|
||||
*/
|
||||
void
|
||||
oc_curl_protocols(struct OCGLOBALSTATE* state)
|
||||
{
|
||||
const char* const* proto; /*weird*/
|
||||
curl_version_info_data* curldata;
|
||||
curldata = curl_version_info(CURLVERSION_NOW);
|
||||
for(proto=curldata->protocols;*proto;proto++) {
|
||||
if(strcmp("file",*proto)==0) {state->curl.proto_file=1;break;}
|
||||
if(strcmp("http",*proto)==0) {state->curl.proto_https=1;break;}
|
||||
}
|
||||
if(ocdebug > 0) {
|
||||
oc_log(LOGNOTE,"Curl file:// support = %d",state->curl.proto_file);
|
||||
oc_log(LOGNOTE,"Curl https:// support = %d",state->curl.proto_https);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set various general curl flags */
|
||||
int
|
||||
ocset_curl_flags(OCstate* state)
|
||||
{
|
||||
CURLcode cstat = CURLE_OK;
|
||||
CURL* curl = state->curl;
|
||||
struct OCcurlflags* flags = &state->curlflags;
|
||||
|
||||
#ifdef CURLOPT_ENCODING
|
||||
if (flags->compress) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_ENCODING,"deflate, gzip");
|
||||
if(cstat != CURLE_OK) goto done;
|
||||
OCDBG(1,"CURLOPT_ENCODING=deflate, gzip");
|
||||
}
|
||||
#endif
|
||||
if (flags->cookiejar || flags->cookiefile) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_COOKIESESSION, 1);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG(1,"CURLOPT_COOKIESESSION=1");
|
||||
}
|
||||
if (flags->cookiejar) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_COOKIEJAR, flags->cookiejar);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_COOKIEJAR=%s",flags->cookiejar);
|
||||
}
|
||||
if (flags->cookiefile) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_COOKIEFILE, flags->cookiefile);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_COOKIEFILE=%s",flags->cookiefile);
|
||||
}
|
||||
if (flags->verbose) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_VERBOSE=%ld",1L);
|
||||
}
|
||||
|
||||
if (flags->timeout) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)flags->timeout);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_TIMEOUT=%ld",1L);
|
||||
}
|
||||
|
||||
/* Following are always set */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
OCDBG1(1,"CURLOPT_FOLLOWLOCATION=%ld",1L);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L);
|
||||
OCDBG1(1,"CURLOPT_MAXREDIRS=%ld",10L);
|
||||
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, state->error.curlerrorbuf);
|
||||
OCDBG1(1,"CURLOPT_ERRORBUFFER",0);
|
||||
|
||||
done:
|
||||
return cstat;
|
||||
}
|
||||
|
||||
int
|
||||
ocset_proxy(OCstate* state)
|
||||
{
|
||||
CURLcode cstat;
|
||||
CURL* curl = state->curl;
|
||||
struct OCproxy *proxy = &state->proxy;
|
||||
struct OCcredentials *creds = &state->creds;
|
||||
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_PROXY, proxy->host);
|
||||
if (cstat != CURLE_OK) return OC_ECURL;
|
||||
OCDBG1(1,"CURLOPT_PROXY=%s",proxy->host);
|
||||
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy->port);
|
||||
if (cstat != CURLE_OK) return OC_ECURL;
|
||||
OCDBG1(1,"CURLOPT_PROXYPORT=%d",proxy->port);
|
||||
|
||||
if (creds->username) {
|
||||
char *combined = combinecredentials(creds->username,creds->password);
|
||||
if (!combined) return OC_ENOMEM;
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, combined);
|
||||
if (cstat != CURLE_OK) return OC_ECURL;
|
||||
OCDBG1(1,"CURLOPT_PROXYUSERPWD=%s",combined);
|
||||
#ifdef CURLOPT_PROXYAUTH
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_PROXYAUTH=%ld",(long)CURLAUTH_ANY);
|
||||
#endif
|
||||
free(combined);
|
||||
}
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
int
|
||||
ocset_ssl(OCstate* state)
|
||||
{
|
||||
CURLcode cstat = CURLE_OK;
|
||||
CURL* curl = state->curl;
|
||||
struct OCSSL* ssl = &state->ssl;
|
||||
long verify = (ssl->validate?1L:0L);
|
||||
cstat=curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, verify);
|
||||
if (cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSL_VERIFYPEER=%ld",verify);
|
||||
cstat=curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (verify?2L:0L));
|
||||
if (cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSL_VERIFYHOST=%ld",(verify?2L:0L));
|
||||
#ifdef OCIGNORE
|
||||
if(verify)
|
||||
#endif
|
||||
{
|
||||
if(ssl->certificate) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_SSLCERT, ssl->certificate);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSLCERT=%s",ssl->certificate);
|
||||
}
|
||||
if(ssl->key) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_SSLKEY, ssl->key);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSLKEY=%s",ssl->key);
|
||||
}
|
||||
if(ssl->keypasswd) {
|
||||
/* libcurl prior to 7.16.4 used 'CURLOPT_SSLKEYPASSWD' */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_KEYPASSWD, ssl->keypasswd);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSLKEY=%s",ssl->key);
|
||||
}
|
||||
if(ssl->cainfo) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_CAINFO, ssl->cainfo);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_CAINFO=%s",ssl->cainfo);
|
||||
}
|
||||
if(ssl->capath) {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_CAPATH, ssl->capath);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_CAPATH=%s",ssl->capath);
|
||||
}
|
||||
{
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, ssl->verifypeer);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
OCDBG1(1,"CURLOPT_SSL_VERIFYPEER=%d",ssl->verifypeer);
|
||||
}
|
||||
}
|
||||
return OC_NOERR;
|
||||
|
||||
fail:
|
||||
return OC_ECURL;
|
||||
}
|
||||
|
||||
/* This is called with arguments while the other functions in this file are
|
||||
* used with global values read from the.dodsrc file. The reason is that
|
||||
* we may have multiple password sources.
|
||||
*/
|
||||
int
|
||||
ocset_user_password(OCstate* state)
|
||||
{
|
||||
CURLcode cstat;
|
||||
CURL* curl = state->curl;
|
||||
char* combined = NULL;
|
||||
const char* userC = state->creds.username;
|
||||
const char* passwordC = state->creds.password;
|
||||
|
||||
if(userC == NULL || passwordC == NULL) return OC_NOERR;
|
||||
|
||||
combined = combinecredentials(userC,passwordC);
|
||||
if (!combined) return OC_ENOMEM;
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_USERPWD, combined);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_USERPWD=%s",combined);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long) CURLAUTH_ANY);
|
||||
if (cstat != CURLE_OK) goto done;
|
||||
OCDBG1(1,"CURLOPT_HTTPAUTH=%ld",(long)CURLAUTH_ANY);
|
||||
|
||||
done:
|
||||
if(combined != NULL) free(combined);
|
||||
return (cstat == CURLE_OK?OC_NOERR:OC_ECURL);
|
||||
}
|
||||
|
||||
|
||||
static char*
|
||||
combinecredentials(const char* user, const char* pwd)
|
||||
{
|
||||
int userPassSize = strlen(user) + strlen(pwd) + 2;
|
||||
char *userPassword = malloc(sizeof(char) * userPassSize);
|
||||
if (!userPassword) {
|
||||
oc_log(LOGERR,"Out of Memory\n");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(userPassword, user);
|
||||
strcat(userPassword, ":");
|
||||
strcat(userPassword, pwd);
|
||||
return userPassword;
|
||||
}
|
23
oc2/occurlfunctions.h
Normal file
23
oc2/occurlfunctions.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* occurlfunction.h
|
||||
*
|
||||
* Created on: Mar 5, 2009
|
||||
* Author: rikki
|
||||
*/
|
||||
|
||||
#ifndef _CURLFUNCTION_H_
|
||||
#define _CURLFUNCTION_H_
|
||||
|
||||
extern void oc_curl_protocols(struct OCGLOBALSTATE*);
|
||||
extern int ocset_curl_flags(OCstate*);
|
||||
extern int ocset_user_password(OCstate*);
|
||||
extern int ocset_proxy(OCstate*);
|
||||
extern int ocset_ssl(OCstate*);
|
||||
extern void oc_curl_setup(OCstate* state);
|
||||
extern void oc_curl_debug(OCstate* state);
|
||||
extern void oc_curl_printerror(OCstate* state);
|
||||
|
||||
#endif /*_CURLFUNCTION_H_*/
|
||||
|
||||
|
||||
|
410
oc2/ocdata.c
Normal file
410
oc2/ocdata.c
Normal file
@ -0,0 +1,410 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "ocdump.h"
|
||||
|
||||
/* Forward*/
|
||||
static OCerror ocread(OCdata*, XXDR*, char*, size_t, size_t, size_t);
|
||||
|
||||
#ifdef OCDEBUG
|
||||
|
||||
static void
|
||||
octrace(char* proc, OCstate* state, OCdata* data)
|
||||
{
|
||||
OCbytes* buffer = ocbytesnew();
|
||||
ocdumpdatapath(state,data,buffer);
|
||||
fprintf(stderr,"%s: %s\n",proc,ocbytescontents(buffer));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define octrace(proc,state,data)
|
||||
#endif /*OCDEBUG*/
|
||||
|
||||
/* Use this to attach to a data tree for a DATADDS */
|
||||
OCerror
|
||||
ocdata_getroot(OCstate* state, OCnode* root, OCdata** datap)
|
||||
{
|
||||
OCdata* data;
|
||||
assert(root->tree->dxdclass == OCDATADDS);
|
||||
assert(root->octype == OC_Dataset);
|
||||
|
||||
if(root->tree->data.data == NULL)
|
||||
return OCTHROW(OC_ENODATA);
|
||||
|
||||
data = root->tree->data.data;
|
||||
if(datap) *datap = data;
|
||||
|
||||
octrace("attach",state,data);
|
||||
|
||||
return OCTHROW(OC_NOERR);
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_container(OCstate* state, OCdata* data, OCdata** containerp)
|
||||
{
|
||||
OCdata* container;
|
||||
OCnode* template;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
|
||||
template = data->template;
|
||||
|
||||
if(template->container == NULL)
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
container = data->container;
|
||||
if(container == NULL)
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
if(containerp) *containerp = container;
|
||||
|
||||
octrace("container", state, container);
|
||||
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_root(OCstate* state, OCdata* data, OCdata** rootp)
|
||||
{
|
||||
OCdata* root;
|
||||
OCnode* template;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
|
||||
template = data->template;
|
||||
root = template->tree->data.data;
|
||||
if(rootp) *rootp = root;
|
||||
|
||||
octrace("root", state, root);
|
||||
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_ithfield(OCstate* state, OCdata* container, size_t index, OCdata** fieldp)
|
||||
{
|
||||
OCdata* field;
|
||||
OCnode* template;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(container != NULL);
|
||||
|
||||
template = container->template;
|
||||
|
||||
if(!iscontainer(template->octype))
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
/* Validate index */
|
||||
if(index >= container->ninstances)
|
||||
return OCTHROW(OC_EINDEX);
|
||||
|
||||
field = container->instances[index];
|
||||
if(fieldp) *fieldp = field;
|
||||
|
||||
octrace("ithfield", state, field);
|
||||
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_ithelement(OCstate* state, OCdata* data, size_t* indices, OCdata** elementp)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
OCdata* element;
|
||||
OCnode* template;
|
||||
size_t index,rank;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(data != NULL);
|
||||
|
||||
template = data->template;
|
||||
rank = template->array.rank;
|
||||
|
||||
/* Must be a dimensioned Structure */
|
||||
if(template->octype != OC_Structure || rank == 0)
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
/* Validate indices */
|
||||
if(!ocvalidateindices(rank,template->array.sizes,indices))
|
||||
return OCTHROW(OC_EINVALCOORDS);
|
||||
|
||||
/* compute linearized index */
|
||||
index = ocarrayoffset(rank,template->array.sizes,indices);
|
||||
|
||||
if(index >= data->ninstances)
|
||||
return OCTHROW(OC_EINDEX);
|
||||
|
||||
element = data->instances[index];
|
||||
|
||||
if(elementp) *elementp = element;
|
||||
|
||||
octrace("ithelement", state, element);
|
||||
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
/* Move to the ith sequence record. */
|
||||
OCerror
|
||||
ocdata_ithrecord(OCstate* state, OCdata* data,
|
||||
size_t index, /* record number */
|
||||
OCdata** recordp
|
||||
)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
OCdata* record;
|
||||
OCnode* template;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(data != NULL);
|
||||
|
||||
template = data->template;
|
||||
|
||||
/* Must be a Sequence */
|
||||
if(template->octype != OC_Sequence
|
||||
|| !fisset(data->datamode,OCDT_SEQUENCE))
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
/* Validate index */
|
||||
if(index >= data->ninstances)
|
||||
return OCTHROW(OC_EINDEX);
|
||||
|
||||
record = data->instances[index];
|
||||
|
||||
if(recordp) *recordp = record;
|
||||
|
||||
octrace("ithrecord", state, record);
|
||||
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_position(OCstate* state, OCdata* data, size_t* indices)
|
||||
{
|
||||
OCnode* template;
|
||||
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(data != NULL);
|
||||
OCASSERT(indices != NULL);
|
||||
|
||||
template = data->template;
|
||||
if(fisset(data->datamode,OCDT_RECORD))
|
||||
indices[0] = data->index;
|
||||
else if(fisset(data->datamode,OCDT_ELEMENT)) {
|
||||
/* Transform the linearized array index into a set of indices */
|
||||
ocarrayindices(data->index,template->array.rank,template->array.sizes,indices);
|
||||
} else
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
return OCTHROW(OC_NOERR);
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocdata_recordcount(OCstate* state, OCdata* data, size_t* countp)
|
||||
{
|
||||
OCASSERT(state != NULL);
|
||||
OCASSERT(data != NULL);
|
||||
OCASSERT(countp != NULL);
|
||||
|
||||
if(data->template->octype != OC_Sequence
|
||||
|| !fisset(data->datamode,OCDT_SEQUENCE))
|
||||
return OCTHROW(OC_EBADTYPE);
|
||||
|
||||
*countp = data->ninstances;
|
||||
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/*
|
||||
In order to actually extract data, one must move to the
|
||||
specific primitive typed field containing the data of
|
||||
interest by using ocdata_fieldith(). Then this procedure
|
||||
is invoked to extract some subsequence of items from the
|
||||
field. For scalars, the start and count are ignored.
|
||||
Note that start and count are linearized from the oc_data_read
|
||||
arguments.
|
||||
*/
|
||||
|
||||
int
|
||||
ocdata_read(OCstate* state, OCdata* data, size_t start, size_t count,
|
||||
void* memory, size_t memsize)
|
||||
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
XXDR* xdrs;
|
||||
OCtype etype, octype;
|
||||
int isscalar;
|
||||
size_t elemsize, totalsize, countsize;
|
||||
OCnode* template;
|
||||
|
||||
octrace("read", state, data);
|
||||
|
||||
assert(state != NULL);
|
||||
assert(data != NULL);
|
||||
assert(memory != NULL);
|
||||
assert(memsize > 0);
|
||||
|
||||
data = data;
|
||||
template = data->template;
|
||||
octype = template->octype;
|
||||
assert(octype == OC_Atomic);
|
||||
etype = template->etype;
|
||||
|
||||
isscalar = (template->array.rank == 0 ? 1 : 0);
|
||||
|
||||
/* validate memory space*/
|
||||
elemsize = octypesize(etype);
|
||||
totalsize = elemsize*data->ninstances;
|
||||
countsize = elemsize*count;
|
||||
if(totalsize < countsize || memsize < countsize)
|
||||
return OCTHROW(OC_EINVAL);
|
||||
|
||||
/* Get XXDR* */
|
||||
xdrs = template->root->tree->data.xdrs;
|
||||
|
||||
if(isscalar) {
|
||||
/* Extract the data */
|
||||
stat = ocread(data,xdrs,(char*)memory,memsize,0,1);
|
||||
} else {
|
||||
/* Validate the start and count */
|
||||
if(start >= data->ninstances
|
||||
|| (start+count) > data->ninstances)
|
||||
return OCTHROW(OC_EINVALCOORDS);
|
||||
/* Extract the data */
|
||||
stat = ocread(data,xdrs,(char*)memory,memsize,start,count);
|
||||
}
|
||||
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/*
|
||||
Extract data from a leaf into memory.
|
||||
*/
|
||||
|
||||
static OCerror
|
||||
ocread(OCdata* data, XXDR* xdrs, char* memory, size_t memsize, size_t start, size_t count)
|
||||
{
|
||||
int i;
|
||||
OCnode* template;
|
||||
OCtype etype;
|
||||
off_t elemsize, totalsize, xdrtotal, xdrstart;
|
||||
int scalar;
|
||||
|
||||
OCASSERT(data != NULL);
|
||||
OCASSERT(memory != NULL);
|
||||
OCASSERT(memsize > 0);
|
||||
OCASSERT(count > 0);
|
||||
OCASSERT((start+count) <= data->ninstances);
|
||||
|
||||
template = data->template;
|
||||
etype = template->etype;
|
||||
scalar = (template->array.rank == 0);
|
||||
|
||||
/* Note that for strings, xdrsize == 0 */
|
||||
xdrtotal = count*data->xdrsize; /* amount (in xdr sizes) to read */
|
||||
xdrstart = start*data->xdrsize; /* offset from the start of the data */
|
||||
|
||||
elemsize = octypesize(etype); /* wrt memory, not xdrsize */
|
||||
totalsize = elemsize*count;
|
||||
|
||||
/* validate memory space*/
|
||||
if(memsize < totalsize) return OCTHROW(OC_EINVAL);
|
||||
|
||||
/* copy out with appropriate byte-order conversions */
|
||||
switch (etype) {
|
||||
|
||||
case OC_Int32: case OC_UInt32: case OC_Float32:
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
if(!xxdr_network_order) {
|
||||
unsigned int* p;
|
||||
for(p=(unsigned int*)memory,i=0;i<count;i++,p++) {
|
||||
swapinline32(p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OC_Int64: case OC_UInt64:
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
if(!xxdr_network_order) {
|
||||
unsigned long long* llp;
|
||||
for(llp=(unsigned long long*)memory,i=0;i<count;i++,llp++) {
|
||||
swapinline64(llp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OC_Float64:
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
{
|
||||
double* dp;
|
||||
for(dp=(double*)memory,i=0;i<count;i++,dp++) {
|
||||
double swap;
|
||||
xxdrntohdouble((char*)dp,&swap);
|
||||
*dp = swap;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* non-packed fixed length, but memory size < xdrsize */
|
||||
case OC_Int16: case OC_UInt16: {
|
||||
/* In order to avoid allocating a lot of space, we do this one int at a time */
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(scalar) {
|
||||
if(!xxdr_ushort(xdrs,(unsigned short*)memory)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
} else {
|
||||
unsigned short* sp = (unsigned short*)memory;
|
||||
for(i=0;i<count;i++,sp++) {
|
||||
if(!xxdr_ushort(xdrs,sp)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
/* Do the byte types, packed/unpacked */
|
||||
case OC_Byte:
|
||||
case OC_UByte:
|
||||
case OC_Char:
|
||||
if(scalar) {
|
||||
/* scalar bytes are stored in xdr as int */
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(!xxdr_uchar(xdrs,(unsigned char*)memory)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
} else {
|
||||
/* the xdroffset will always be at the start of the
|
||||
packed data, so we need to add the start count to it */
|
||||
xxdr_setpos(xdrs,data->xdroffset+xdrstart);
|
||||
if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Hard case, because strings are variable length */
|
||||
case OC_String: case OC_URL: {
|
||||
/* use the data->nstrings data->string fields */
|
||||
char** sp = (char**)memory;
|
||||
if(count > data->nstrings)
|
||||
return OCTHROW(OC_EDATADDS);
|
||||
for(i=0;i<count;i++,sp++) {
|
||||
off_t len;
|
||||
size_t offset = data->strings[start+i];
|
||||
xxdr_setpos(xdrs,offset);
|
||||
/* get the string */
|
||||
if(!xxdr_string(xdrs,sp,&len))
|
||||
{OCTHROW(OC_EDATADDS); goto xdrfail;}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: OCPANIC("unexpected etype"); break;
|
||||
}
|
||||
|
||||
return OC_NOERR;
|
||||
|
||||
xdrfail:
|
||||
oc_log(LOGERR,"DAP DATADDS packet is apparently too short");
|
||||
return OCTHROW(OC_EDATADDS);
|
||||
}
|
||||
|
48
oc2/ocdata.h
Normal file
48
oc2/ocdata.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCDATA_H
|
||||
#define OCDATA_H
|
||||
|
||||
/*
|
||||
This structure is used to set up
|
||||
pointers into the DataDDS data packet
|
||||
to speed up access.
|
||||
This has some similarities to OCNODE.
|
||||
*/
|
||||
|
||||
struct OCdata {
|
||||
OCheader header;
|
||||
OCDT datamode;
|
||||
OCnode* template;
|
||||
OCdata* container; /* link back to container instance */
|
||||
size_t index; /* WRT to the container */
|
||||
off_t xdroffset; /* Of this instance wrt xxdr_getpos() */
|
||||
off_t xdrsize; /* for leafs, and as defined by xdr; if known else 0*/
|
||||
size_t ninstances;/* |instances| */
|
||||
OCdata** instances; /* vector of instances; if rank > 0, then
|
||||
it captures the array elements, else
|
||||
it captures the field instances. */
|
||||
off_t nstrings;
|
||||
off_t* strings;
|
||||
};
|
||||
|
||||
|
||||
extern void ocdata_free(OCstate*, OCdata*);
|
||||
|
||||
extern OCerror ocdata_ithfield(OCstate*, OCdata* container, size_t index, OCdata** fieldp);
|
||||
extern OCerror ocdata_container(OCstate*, OCdata* data, OCdata** containerp);
|
||||
extern OCerror ocdata_root(OCstate*, OCdata* data, OCdata** rootp);
|
||||
|
||||
extern OCerror ocdata_ithelement(OCstate*, OCdata* data, size_t* indices, OCdata** elementp);
|
||||
extern OCerror ocdata_ithrecord(OCstate*, OCdata* data, size_t index, OCdata** recordp);
|
||||
|
||||
extern OCerror ocdata_position(OCstate*, OCdata* data, size_t* indices);
|
||||
extern OCerror ocdata_recordcount(OCstate*, OCdata*, size_t*);
|
||||
|
||||
extern OCerror ocdata_getroot(OCstate*, OCnode*, OCdata**);
|
||||
|
||||
/* Atomic leaf reading */
|
||||
extern int ocdata_read(OCstate*,OCdata*,size_t,size_t,void*,size_t);
|
||||
|
||||
#endif /*OCDATA_H*/
|
61
oc2/ocdatatypes.h
Normal file
61
oc2/ocdatatypes.h
Normal file
@ -0,0 +1,61 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCDATATYPES_H
|
||||
#define OCDATATYPES_H
|
||||
|
||||
/* Define some useful info about the supported
|
||||
primitive datatypes*/
|
||||
|
||||
#define DCHAR char
|
||||
#define DBYTE signed char
|
||||
#define DUBYTE unsigned char
|
||||
#define DINT16 short
|
||||
#define DUINT16 unsigned short
|
||||
#define DINT32 int
|
||||
#define DUINT32 unsigned int
|
||||
#define DINT64 int
|
||||
#define DUINT64 unsigned int
|
||||
#define DFLOAT32 float
|
||||
#define DFLOAT64 double
|
||||
|
||||
#define OC_CHAR_MIN ((char)0x00)
|
||||
#define OC_CHAR_MAX ((char)0xff)
|
||||
#define OC_BYTE_MIN -128
|
||||
#define OC_BYTE_MAX 127
|
||||
#define OC_UBYTE_MIN 0
|
||||
#define OC_UBYTE_MAX 255U
|
||||
#define OC_INT16_MIN -32768
|
||||
#define OC_INT16_MAX 32767
|
||||
#define OC_UINT16_MIN 0
|
||||
#define OC_UINT16_MAX 65535U
|
||||
#define OC_INT32_MIN (-2147483647 - 1)
|
||||
#define OC_INT32_MAX 2147483647
|
||||
#define OC_UINT32_MIN 0
|
||||
#define OC_UINT32_MAX 4294967295U
|
||||
#define OC_INT64_MIN (-9223372036854775807LL-1)
|
||||
#define OC_INT64_MAX (9223372036854775807LL)
|
||||
#define OC_UINT64_MIN 0LL
|
||||
#define OC_UINT64_MAX (18446744073709551615ULL)
|
||||
#define OC_FLOAT32_MAX 3.402823466E+38F /* max decimal value of a "float" */
|
||||
#define OC_FLOAT32_MIN (-OC_FLOAT_MAX)
|
||||
#define OC_FLOAT64_MAX 1.7976931348623157E+308 /* max decimal value of a double */
|
||||
#define OC_FLOAT64_MIN (-OC_FLOAT64_MAX)
|
||||
|
||||
/* Similar to netcdf*/
|
||||
#define OC_FILL_CHAR ((char)0)
|
||||
#define OC_FILL_BYTE ((signed char)-127)
|
||||
#define OC_FILL_UBYTE (255)
|
||||
#define OC_FILL_INT16 ((short)-32767)
|
||||
#define OC_FILL_UINT16 (65535)
|
||||
#define OC_FILL_INT32 (-2147483647L)
|
||||
#define OC_FILL_UINT32 (4294967295U)
|
||||
#define OC_FILL_INT64 ((long long)-9223372036854775806LL)
|
||||
#define OC_FILL_UINT64 ((unsigned long long)18446744073709551614ULL)
|
||||
#define OC_FILL_FLOAT32 (9.9692099683868690e+36f) /* near 15 * 2^119 */
|
||||
#define OC_FILL_FLOAT64 (9.9692099683868690e+36)
|
||||
#define OC_FILL_STRING ""
|
||||
#define OC_FILL_URL ""
|
||||
|
||||
|
||||
#endif /*OCDATATYPES_H*/
|
67
oc2/ocdebug.c
Normal file
67
oc2/ocdebug.c
Normal file
@ -0,0 +1,67 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include <stdarg.h>
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
|
||||
int ocdebug;
|
||||
|
||||
#ifdef OCCATCHERROR
|
||||
/* Place breakpoint here to catch errors close to where they occur*/
|
||||
int
|
||||
ocbreakpoint(int err) {return err;}
|
||||
|
||||
int
|
||||
octhrow(int err)
|
||||
{
|
||||
if(err == 0) return err;
|
||||
return ocbreakpoint(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
xdrerror(void)
|
||||
{
|
||||
oc_log(LOGERR,"xdr failure");
|
||||
return OCTHROW(OC_EDATADDS);
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
occalloc(size_t size, size_t nelems)
|
||||
{
|
||||
return ocmalloc(size*nelems);
|
||||
}
|
||||
|
||||
void*
|
||||
ocmalloc(size_t size)
|
||||
{
|
||||
void* memory = calloc(size,1); /* use calloc to zero memory*/
|
||||
if(memory == NULL) oc_log(LOGERR,"ocmalloc: out of memory");
|
||||
return memory;
|
||||
}
|
||||
|
||||
void
|
||||
ocfree(void* mem)
|
||||
{
|
||||
if(mem != NULL) free(mem);
|
||||
}
|
||||
|
||||
int
|
||||
ocpanic(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
if(fmt != NULL) {
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n" );
|
||||
va_end( args );
|
||||
} else {
|
||||
fprintf(stderr, "panic" );
|
||||
}
|
||||
fprintf(stderr, "\n" );
|
||||
fflush(stderr);
|
||||
return 0;
|
||||
}
|
94
oc2/ocdebug.h
Normal file
94
oc2/ocdebug.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCOCDBG_H
|
||||
#define OCOCDBG_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if 0
|
||||
#define OCDEBUG
|
||||
#define DAPDEBUG 1
|
||||
#endif
|
||||
|
||||
#ifdef OCDEBUG
|
||||
#define OCVERBOSE
|
||||
#endif
|
||||
|
||||
/* OCCATCHERROR is used to detect errors as close
|
||||
to their point of origin as possible. When
|
||||
enabled, one can set a breakpoint in ocbreakpoint()
|
||||
to catch the failure. Turing it on incurs a significant
|
||||
performance penalty, so it is off by default.*/
|
||||
|
||||
#define OCCATCHERROR
|
||||
|
||||
#define OCPANIC(msg) assert(ocpanic(msg))
|
||||
#define OCPANIC1(msg,arg) assert(ocpanic(msg,arg))
|
||||
#define OCPANIC2(msg,arg1,arg2) assert(ocpanic(msg,arg1,arg2))
|
||||
|
||||
/* Make it possible to catch assertion failures by breakpointing ocpanic*/
|
||||
#define OCASSERT(expr) if(!(expr)) {OCPANIC((#expr));} else {}
|
||||
|
||||
/* Need some syntactic trickery to make these macros work*/
|
||||
#ifdef OCDEBUG
|
||||
#define OCDBG(l,msg) {oc_log(LOGDBG,msg);}
|
||||
#define OCDBG1(l,msg,arg) {oc_log(LOGDBG,msg,arg);}
|
||||
#define OCDBG2(l,msg,arg1,arg2) {oc_log(LOGDBG,msg,arg1,arg2);}
|
||||
#define OCDBGTEXT(l,text) {oc_logtext(LOGNOTE,text);} else {}
|
||||
#define OCDBGCODE(l,code) {code;}
|
||||
#else
|
||||
#define OCDBG(l,msg)
|
||||
#define OCDBG1(l,msg,arg)
|
||||
#define OCDBG2(l,msg,arg1,arg2)
|
||||
#define OCDBGTEXT(l,text)
|
||||
#define OCDBGCODE(l,code)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
OCPROGRESS attempts to provide some info
|
||||
about how IO is getting along.
|
||||
*/
|
||||
#undef OCPROGRESS
|
||||
|
||||
extern int ocdebug;
|
||||
extern int cedebug;
|
||||
|
||||
/*extern char* dent2(int n);*/
|
||||
/*/extern char* dent(int n);*/
|
||||
extern int ocpanic(const char* fmt, ...);
|
||||
|
||||
extern int xdrerror(void);
|
||||
|
||||
/*
|
||||
Provide wrapped versions of calloc and malloc.
|
||||
The wrapped version panics if memory
|
||||
is exhausted. It also guarantees that the
|
||||
memory has been zero'd.
|
||||
*/
|
||||
|
||||
extern void* occalloc(size_t size, size_t nelems);
|
||||
extern void* ocmalloc(size_t size);
|
||||
extern void ocfree(void*);
|
||||
|
||||
#define MEMCHECK(var,throw) {if((var)==NULL) return (throw);}
|
||||
#define MEMFAIL(var) MEMCHECK(var,OCTHROW(OC_ENOMEM))
|
||||
#define MEMGOTO(var,label) {if((var)==NULL) goto label;}
|
||||
|
||||
#ifdef OCCATCHERROR
|
||||
/* Place breakpoint on ocbreakpoint to catch errors close to where they occur*/
|
||||
#define OCTHROW(e) octhrow(e)
|
||||
#define OCTHROWCHK(e) (void)octhrow(e)
|
||||
#define OCGOTO(label) {ocbreakpoint(-1); goto label;}
|
||||
extern int ocbreakpoint(int err);
|
||||
extern int octhrow(int err);
|
||||
#else
|
||||
#define OCTHROW(e) (e)
|
||||
#define OCTHROWCHK(e)
|
||||
#define OCGOTO(label) goto label
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*OCOCDBG_H*/
|
||||
|
650
oc2/ocdump.c
Normal file
650
oc2/ocdump.c
Normal file
@ -0,0 +1,650 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
|
||||
#define MAXLEVEL 1
|
||||
|
||||
/*Forward*/
|
||||
static void dumpocnode1(OCnode* node, int depth);
|
||||
static void dumpdimensions(OCnode* node);
|
||||
static void dumpattvalue(OCtype nctype, char** aset, int index);
|
||||
|
||||
static char* sindent = NULL;
|
||||
|
||||
static char*
|
||||
dent(int n)
|
||||
{
|
||||
if(sindent == NULL) {
|
||||
sindent = (char*)ocmalloc(102);
|
||||
MEMCHECK(sindent,NULL);
|
||||
memset((void*)sindent,(int)' ',(size_t)101);
|
||||
sindent[101] = '\0';
|
||||
}
|
||||
if(n > 100) n = 100;
|
||||
return sindent+(100-n);
|
||||
}
|
||||
|
||||
/* support [dd] leader*/
|
||||
static char*
|
||||
dent2(int n) {return dent(n+4);}
|
||||
|
||||
static void
|
||||
tabto(int pos, OCbytes* buffer)
|
||||
{
|
||||
int bol,len,pad;
|
||||
len = ocbyteslength(buffer);
|
||||
/* find preceding newline */
|
||||
for(bol=len-1;;bol--) {
|
||||
int c = ocbytesget(buffer,bol);
|
||||
if(c < 0) break;
|
||||
if(c == '\n') {bol++; break;}
|
||||
}
|
||||
len = (len - bol);
|
||||
pad = (pos - len);
|
||||
while(pad-- > 0) ocbytescat(buffer," ");
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpnode(OCnode* node)
|
||||
{
|
||||
if(node != NULL) {
|
||||
dumpocnode1(node,0);
|
||||
} else {
|
||||
fprintf(stdout,"<NULL>\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
dumpocnode1(OCnode* node, int depth)
|
||||
{
|
||||
unsigned int n;
|
||||
switch (node->octype) {
|
||||
case OC_Atomic: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
if(node->name == NULL) OCPANIC("prim without name");
|
||||
fprintf(stdout,"%s %s",octypetostring(node->etype),node->name);
|
||||
dumpdimensions(node);
|
||||
fprintf(stdout," &%lx",(unsigned long)node);
|
||||
fprintf(stdout,"\n");
|
||||
} break;
|
||||
|
||||
case OC_Dataset: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
fprintf(stdout,"dataset %s\n",
|
||||
(node->name?node->name:""));
|
||||
for(n=0;n<oclistlength(node->subnodes);n++) {
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,n),depth+1);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OC_Structure: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
fprintf(stdout,"struct %s",
|
||||
(node->name?node->name:""));
|
||||
dumpdimensions(node);
|
||||
fprintf(stdout," &%lx",(unsigned long)node);
|
||||
fprintf(stdout,"\n");
|
||||
for(n=0;n<oclistlength(node->subnodes);n++) {
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,n),depth+1);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OC_Sequence: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
fprintf(stdout,"sequence %s",
|
||||
(node->name?node->name:""));
|
||||
dumpdimensions(node);
|
||||
fprintf(stdout," &%lx",(unsigned long)node);
|
||||
fprintf(stdout,"\n");
|
||||
for(n=0;n<oclistlength(node->subnodes);n++) {
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,n),depth+1);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OC_Grid: {
|
||||
unsigned int i;
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
fprintf(stdout,"grid %s",
|
||||
(node->name?node->name:""));
|
||||
dumpdimensions(node);
|
||||
fprintf(stdout," &%lx",(unsigned long)node);
|
||||
fprintf(stdout,"\n");
|
||||
fprintf(stdout,"%sarray:\n",dent2(depth+1));
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,0),depth+2);
|
||||
fprintf(stdout,"%smaps:\n",dent2(depth+1));
|
||||
for(i=1;i<oclistlength(node->subnodes);i++) {
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,i),depth+2);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OC_Attribute: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
if(node->name == NULL) OCPANIC("Attribute without name");
|
||||
fprintf(stdout,"%s %s",octypetostring(node->etype),node->name);
|
||||
for(n=0;n<oclistlength(node->att.values);n++) {
|
||||
char* value = (char*)oclistget(node->att.values,n);
|
||||
if(n > 0) fprintf(stdout,",");
|
||||
fprintf(stdout," %s",value);
|
||||
}
|
||||
fprintf(stdout," &%lx",(unsigned long)node);
|
||||
fprintf(stdout,"\n");
|
||||
} break;
|
||||
|
||||
case OC_Attributeset: {
|
||||
fprintf(stdout,"[%2d]%s ",depth,dent(depth));
|
||||
fprintf(stdout,"%s:\n",node->name?node->name:"Attributes");
|
||||
for(n=0;n<oclistlength(node->subnodes);n++) {
|
||||
dumpocnode1((OCnode*)oclistget(node->subnodes,n),depth+1);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
OCPANIC1("encountered unexpected node type: %x",node->octype);
|
||||
}
|
||||
|
||||
if(node->attributes != NULL) {
|
||||
unsigned int i;
|
||||
for(i=0;i<oclistlength(node->attributes);i++) {
|
||||
OCattribute* att = (OCattribute*)oclistget(node->attributes,i);
|
||||
fprintf(stdout,"%s[%s=",dent2(depth+2),att->name);
|
||||
if(att->nvalues == 0)
|
||||
OCPANIC("Attribute.nvalues == 0");
|
||||
if(att->nvalues == 1) {
|
||||
dumpattvalue(att->etype,att->values,0);
|
||||
} else {
|
||||
unsigned int j;
|
||||
fprintf(stdout,"{");
|
||||
for(j=0;j<att->nvalues;j++) {
|
||||
if(j>0) fprintf(stdout,", ");
|
||||
dumpattvalue(att->etype,att->values,j);
|
||||
}
|
||||
fprintf(stdout,"}");
|
||||
}
|
||||
fprintf(stdout,"]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dumpdimensions(OCnode* node)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<node->array.rank;i++) {
|
||||
OCnode* dim = (OCnode*)oclistget(node->array.dimensions,i);
|
||||
fprintf(stdout,"[%s=%lu]",
|
||||
(dim->name?dim->name:"?"),
|
||||
(unsigned long)dim->dim.declsize);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dumpattvalue(OCtype nctype, char** strings, int index)
|
||||
{
|
||||
if(nctype == OC_String || nctype == OC_URL) {
|
||||
fprintf(stdout,"\"%s\"",strings[index]);
|
||||
} else {
|
||||
fprintf(stdout,"%s",strings[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpslice(OCslice* slice)
|
||||
{
|
||||
fprintf(stdout,"[");
|
||||
fprintf(stdout,"%lu",(unsigned long)slice->first);
|
||||
if(slice->stride > 1) fprintf(stdout,":%lu",(unsigned long)slice->stride);
|
||||
fprintf(stdout,":%lu",(unsigned long)(slice->first+slice->count)-1);
|
||||
fprintf(stdout,"]");
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpclause(OCprojectionclause* ref)
|
||||
{
|
||||
unsigned int i;
|
||||
OClist* path = oclistnew();
|
||||
occollectpathtonode(ref->node,path);
|
||||
for(i=0;i<oclistlength(path);i++) {
|
||||
OClist* sliceset;
|
||||
OCnode* node = (OCnode*)oclistget(path,i);
|
||||
if(node->tree != NULL) continue; /* leave off the root node*/
|
||||
fprintf(stdout,"%s%s",(i>0?PATHSEPARATOR:""),node->name);
|
||||
sliceset = (OClist*)oclistget(ref->indexsets,i);
|
||||
if(sliceset != NULL) {
|
||||
unsigned int j;
|
||||
for(j=0;j<oclistlength(sliceset);j++) {
|
||||
OCslice* slice = (OCslice*)oclistget(sliceset,j);
|
||||
ocdumpslice(slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addfield(char* field, char* line, int align)
|
||||
{
|
||||
int len,rem;
|
||||
strcat(line,"|");
|
||||
strcat(line,field);
|
||||
len = strlen(field);
|
||||
rem = (align - len);
|
||||
while(rem-- > 0) strcat(line," ");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpfield(int index, char* n8, int isxdr)
|
||||
{
|
||||
char line[1024];
|
||||
char tmp[32];
|
||||
|
||||
union {
|
||||
unsigned int uv;
|
||||
int sv;
|
||||
char cv[4];
|
||||
float fv;
|
||||
} form;
|
||||
union {
|
||||
char cv[8];
|
||||
unsigned long long ll;
|
||||
double d;
|
||||
} dform;
|
||||
|
||||
line[0] = '\0';
|
||||
|
||||
/* offset */
|
||||
sprintf(tmp,"%6d",index);
|
||||
addfield(tmp,line,5);
|
||||
|
||||
memcpy(form.cv,n8,4);
|
||||
|
||||
/* straight hex*/
|
||||
sprintf(tmp,"%08x",form.uv);
|
||||
addfield(tmp,line,8);
|
||||
|
||||
if(isxdr) {swapinline32(&form.uv);}
|
||||
|
||||
/* unsigned integer */
|
||||
sprintf(tmp,"%12u",form.uv);
|
||||
addfield(tmp,line,12);
|
||||
|
||||
/* signed integer */
|
||||
sprintf(tmp,"%12d",form.sv);
|
||||
addfield(tmp,line,12);
|
||||
|
||||
/* float */
|
||||
sprintf(tmp,"%#g",form.fv);
|
||||
addfield(tmp,line,12);
|
||||
|
||||
/* char[4] */
|
||||
{
|
||||
/* use raw form (i.e. n8)*/
|
||||
int i;
|
||||
tmp[0] = '\0';
|
||||
for(i=0;i<4;i++) {
|
||||
char stmp[64];
|
||||
unsigned int c = (n8[i] & 0xff);
|
||||
if(c < ' ' || c > 126)
|
||||
sprintf(stmp,"\\%02x",c);
|
||||
else
|
||||
sprintf(stmp,"%c",c);
|
||||
strcat(tmp,stmp);
|
||||
}
|
||||
}
|
||||
|
||||
addfield(tmp,line,16);
|
||||
|
||||
/* double */
|
||||
memcpy(dform.cv,n8,2*XDRUNIT);
|
||||
if(isxdr) xxdrntohdouble(dform.cv,&dform.d);
|
||||
sprintf(tmp,"%#g",dform.d);
|
||||
addfield(tmp,line,12);
|
||||
|
||||
fprintf(stdout,"%s\n",line);
|
||||
}
|
||||
|
||||
static void
|
||||
typedmemorydump(char* memory, size_t len, int fromxdr)
|
||||
{
|
||||
unsigned int i,count,rem;
|
||||
char line[1024];
|
||||
char* pmem;
|
||||
char mem[8];
|
||||
|
||||
assert(memory[len] == 0);
|
||||
|
||||
/* build the header*/
|
||||
line[0] = '\0';
|
||||
addfield("offset",line,6);
|
||||
addfield("hex",line,8);
|
||||
addfield("uint",line,12);
|
||||
addfield("int",line,12);
|
||||
addfield("float",line,12);
|
||||
addfield("char[4]",line,16);
|
||||
addfield("double",line,12);
|
||||
strcat(line,"\n");
|
||||
fprintf(stdout,"%s",line);
|
||||
|
||||
count = (len / sizeof(int));
|
||||
rem = (len % sizeof(int));
|
||||
|
||||
for(pmem=memory,i=0;i<count;i++,pmem+=4) {
|
||||
memset(mem,0,8);
|
||||
if(i<(count-1))
|
||||
memcpy(mem,pmem,8);
|
||||
else
|
||||
memcpy(mem,pmem,4);
|
||||
dumpfield(i*sizeof(unsigned int),mem,fromxdr);
|
||||
}
|
||||
if(rem > 0) {
|
||||
memset(mem,0,8);
|
||||
memcpy(mem,pmem,4);
|
||||
dumpfield(i*sizeof(unsigned int),mem,fromxdr);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
simplememorydump(char* memory, size_t len, int fromxdr)
|
||||
{
|
||||
unsigned int i,count,rem;
|
||||
int* imemory;
|
||||
char tmp[32];
|
||||
char line[1024];
|
||||
|
||||
assert(memory[len] == 0);
|
||||
|
||||
/* build the header*/
|
||||
line[0] = '\0';
|
||||
addfield("offset",line,6);
|
||||
addfield("XDR (hex)",line,9);
|
||||
addfield("!XDR (hex)",line,10);
|
||||
fprintf(stdout,"%s\n",line);
|
||||
|
||||
count = (len / sizeof(int));
|
||||
rem = (len % sizeof(int));
|
||||
if(rem != 0)
|
||||
fprintf(stderr,"ocdump: |mem|%%4 != 0\n");
|
||||
imemory = (int*)memory;
|
||||
|
||||
for(i=0;i<count;i++) {
|
||||
unsigned int vx = (unsigned int)imemory[i];
|
||||
unsigned int v = vx;
|
||||
if(!xxdr_network_order) swapinline32(&v);
|
||||
line[0] = '\0';
|
||||
sprintf(tmp,"%6d",i);
|
||||
addfield(tmp,line,6);
|
||||
sprintf(tmp,"%08x",vx);
|
||||
addfield(tmp,line,9);
|
||||
sprintf(tmp,"%08x",v);
|
||||
addfield(tmp,line,10);
|
||||
fprintf(stdout,"%s\n",line);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpmemory(char* memory, size_t len, int xdrencoded, int level)
|
||||
{
|
||||
if(level > MAXLEVEL) level = MAXLEVEL;
|
||||
switch (level) {
|
||||
case 1: /* Do a multi-type dump */
|
||||
typedmemorydump(memory,len,xdrencoded);
|
||||
break;
|
||||
case 0: /* Dump a simple linear list of the contents of the memory as 32-bit hex and decimal */
|
||||
default:
|
||||
simplememorydump(memory,len,xdrencoded);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ocreadfile(FILE* file, int datastart, char** memp, size_t* lenp)
|
||||
{
|
||||
char* mem;
|
||||
size_t len;
|
||||
size_t pos;
|
||||
size_t red;
|
||||
struct stat stats;
|
||||
|
||||
pos = ftell(file);
|
||||
fseek(file,0,SEEK_SET);
|
||||
fseek(file,datastart,SEEK_SET);
|
||||
|
||||
fstat(fileno(file),&stats);
|
||||
len = stats.st_size;
|
||||
len -= datastart;
|
||||
|
||||
mem = (char*)calloc(len+1,1);
|
||||
if(mem == NULL) return 0;
|
||||
|
||||
/* Read only the data part */
|
||||
red = fread(mem,1,len,file);
|
||||
if(red < len) {
|
||||
fprintf(stderr,"ocreadfile: short file\n");
|
||||
return 0;
|
||||
}
|
||||
fseek(file,pos,SEEK_SET); /* leave it as we found it*/
|
||||
if(memp) *memp = mem;
|
||||
if(lenp) *lenp = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ocdd(OCstate* state, OCnode* root, int xdrencoded, int level)
|
||||
{
|
||||
char* mem;
|
||||
size_t len;
|
||||
if(root->tree->data.file != NULL) {
|
||||
if(!ocreadfile(root->tree->data.file,root->tree->data.bod,&mem,&len)) {
|
||||
fprintf(stderr,"ocdd could not read data file\n");
|
||||
return;
|
||||
}
|
||||
ocdumpmemory(mem,len,xdrencoded,level);
|
||||
free(mem);
|
||||
} else {
|
||||
mem = root->tree->data.memory;
|
||||
mem += root->tree->data.bod;
|
||||
len = root->tree->data.datasize;
|
||||
len -= root->tree->data.bod;
|
||||
ocdumpmemory(mem,len,xdrencoded,level);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpdata(OCstate* state, OCdata* data, OCbytes* buffer, int frominstance)
|
||||
{
|
||||
char tmp[1024];
|
||||
OCnode* template = data->template;
|
||||
snprintf(tmp,sizeof(tmp),"%lx:",(unsigned long)data);
|
||||
ocbytescat(buffer,tmp);
|
||||
if(!frominstance) {
|
||||
ocbytescat(buffer," node=");
|
||||
ocbytescat(buffer,template->name);
|
||||
}
|
||||
snprintf(tmp,sizeof(tmp)," xdroffset=%ld",(unsigned long)data->xdroffset);
|
||||
ocbytescat(buffer,tmp);
|
||||
if(data->template->octype == OC_Atomic) {
|
||||
snprintf(tmp,sizeof(tmp)," xdrsize=%ld",(unsigned long)data->xdrsize);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
if(iscontainer(template->octype)) {
|
||||
snprintf(tmp,sizeof(tmp)," ninstances=%d",(int)data->ninstances);
|
||||
ocbytescat(buffer,tmp);
|
||||
} else if(template->etype == OC_String || template->etype == OC_URL) {
|
||||
snprintf(tmp,sizeof(tmp)," nstrings=%d",(int)data->nstrings);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
ocbytescat(buffer," container=");
|
||||
snprintf(tmp,sizeof(tmp),"%lx",(unsigned long)data->container);
|
||||
ocbytescat(buffer,tmp);
|
||||
ocbytescat(buffer," mode=");
|
||||
ocbytescat(buffer,ocdtmodestring(data->datamode,0));
|
||||
}
|
||||
|
||||
/*
|
||||
Depth Offset Index Flags Size Type Name
|
||||
0123456789012345678901234567890123456789012345
|
||||
0 1 2 3 4
|
||||
[001] 00000000 0000 FS 0000 Structure person
|
||||
*/
|
||||
static const int tabstops[] = {0,6,15,21,27,32,42};
|
||||
static const char* header =
|
||||
"Depth Offset Index Flags Size Type Name\n";
|
||||
|
||||
void
|
||||
ocdumpdatatree(OCstate* state, OCdata* data, OCbytes* buffer, int depth)
|
||||
{
|
||||
size_t i,rank;
|
||||
OCnode* template;
|
||||
char tmp[1024];
|
||||
size_t crossproduct;
|
||||
int tabstop = 0;
|
||||
const char* typename;
|
||||
|
||||
/* If this is the first call, then dump a header line */
|
||||
if(depth == 0) {
|
||||
ocbytescat(buffer,header);
|
||||
}
|
||||
|
||||
/* get info about the template */
|
||||
template = data->template;
|
||||
rank = template->array.rank;
|
||||
|
||||
/* get total dimension size */
|
||||
if(rank > 0)
|
||||
crossproduct = octotaldimsize(template->array.rank,template->array.sizes);
|
||||
|
||||
/* Dump the depth first */
|
||||
snprintf(tmp,sizeof(tmp),"[%03d]",depth);
|
||||
ocbytescat(buffer,tmp);
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
snprintf(tmp,sizeof(tmp),"%08lu",(unsigned long)data->xdroffset);
|
||||
ocbytescat(buffer,tmp);
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
/* Dump the Index wrt to parent, if defined */
|
||||
if(fisset(data->datamode,OCDT_FIELD)
|
||||
|| fisset(data->datamode,OCDT_ELEMENT)
|
||||
|| fisset(data->datamode,OCDT_RECORD)) {
|
||||
snprintf(tmp,sizeof(tmp),"%04lu ",(unsigned long)data->index);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
/* Dump the mode flags in compact form */
|
||||
ocbytescat(buffer,ocdtmodestring(data->datamode,1));
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
/* Dump the size or ninstances */
|
||||
if(fisset(data->datamode,OCDT_ARRAY)
|
||||
|| fisset(data->datamode,OCDT_SEQUENCE)) {
|
||||
snprintf(tmp,sizeof(tmp),"%04lu",(unsigned long)data->ninstances);
|
||||
} else {
|
||||
snprintf(tmp,sizeof(tmp),"%04lu",(unsigned long)data->xdrsize);
|
||||
}
|
||||
ocbytescat(buffer,tmp);
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
if(template->octype == OC_Atomic) {
|
||||
typename = octypetoddsstring(template->etype);
|
||||
} else { /*must be container*/
|
||||
typename = octypetoddsstring(template->octype);
|
||||
}
|
||||
ocbytescat(buffer,typename);
|
||||
|
||||
tabto(tabstops[++tabstop],buffer);
|
||||
|
||||
snprintf(tmp,sizeof(tmp),"%s",template->name);
|
||||
ocbytescat(buffer,tmp);
|
||||
|
||||
if(rank > 0) {
|
||||
snprintf(tmp,sizeof(tmp),"[%lu]",(unsigned long)crossproduct);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
ocbytescat(buffer,"\n");
|
||||
|
||||
/* dump the sub-instance, which might be fields, records, or elements */
|
||||
if(!fisset(data->datamode,OCDT_ATOMIC)) {
|
||||
for(i=0;i<data->ninstances;i++)
|
||||
ocdumpdatatree(state,data->instances[i],buffer,depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ocdumpdatapath(OCstate* state, OCdata* data, OCbytes* buffer)
|
||||
{
|
||||
int i;
|
||||
OCdata* path[1024];
|
||||
char tmp[1024];
|
||||
OCdata* pathdata;
|
||||
OCnode* template;
|
||||
int isrecord;
|
||||
|
||||
path[0] = data;
|
||||
for(i=1;;i++) {
|
||||
OCdata* next = path[i-1];
|
||||
if(next->container == NULL) break;
|
||||
path[i] = next->container;
|
||||
}
|
||||
/* Path is in reverse order */
|
||||
for(i=i-1;i>=0;i--) {
|
||||
pathdata = path[i];
|
||||
template = pathdata->template;
|
||||
ocbytescat(buffer,"/");
|
||||
ocbytescat(buffer,template->name);
|
||||
/* Check the mode of the next step in path */
|
||||
if(i > 0) {
|
||||
OCdata* next = path[i-1];
|
||||
if(fisset(next->datamode,OCDT_FIELD)
|
||||
|| fisset(next->datamode,OCDT_ELEMENT)
|
||||
|| fisset(next->datamode,OCDT_RECORD)) {
|
||||
snprintf(tmp,sizeof(tmp),".%lu",next->index);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
}
|
||||
if(template->octype == OC_Atomic) {
|
||||
if(template->array.rank > 0) {
|
||||
off_t xproduct = octotaldimsize(template->array.rank,template->array.sizes);
|
||||
snprintf(tmp,sizeof(tmp),"[0..%lu]",(unsigned long)xproduct-1);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
||||
}
|
||||
isrecord = 0;
|
||||
if(template->octype == OC_Sequence) {
|
||||
/* Is this a record or a sequence ? */
|
||||
isrecord = (fisset(pathdata->datamode,OCDT_RECORD) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
/* Add suffix to path */
|
||||
if(iscontainer(template->octype)) {
|
||||
/* add the container type, except distinguish record and sequence */
|
||||
ocbytescat(buffer,":");
|
||||
if(isrecord)
|
||||
ocbytescat(buffer,"Record");
|
||||
else
|
||||
ocbytescat(buffer,octypetoddsstring(template->octype));
|
||||
} else if(isatomic(template->octype)) {
|
||||
/* add the atomic etype */
|
||||
ocbytescat(buffer,":");
|
||||
ocbytescat(buffer,octypetoddsstring(template->etype));
|
||||
}
|
||||
snprintf(tmp,sizeof(tmp),"->0x%0lx",(unsigned long)pathdata);
|
||||
ocbytescat(buffer,tmp);
|
||||
}
|
21
oc2/ocdump.h
Normal file
21
oc2/ocdump.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCDUMP_H
|
||||
#define OCDUMP_H
|
||||
|
||||
extern void ocdumpnode(OCnode* node);
|
||||
|
||||
extern void ocdumpslice(OCslice* slice);
|
||||
extern void ocdumpclause(OCprojectionclause* ref);
|
||||
|
||||
extern void ocdumpmemory(char* memory, size_t len, int xdrencoded, int level);
|
||||
|
||||
extern void ocdd(OCstate*,OCnode*,int xdrencoded, int level);
|
||||
|
||||
extern void ocdumpdata(OCstate*,OCdata*,OCbytes*,int);
|
||||
|
||||
extern void ocdumpdatatree(OCstate*, struct OCdata*, OCbytes* buffer, int depth);
|
||||
extern void ocdumpdatapath(OCstate*, struct OCdata*, OCbytes* buffer);
|
||||
|
||||
#endif /*OCDUMP_H*/
|
338
oc2/ochttp.c
Normal file
338
oc2/ochttp.c
Normal file
@ -0,0 +1,338 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "ochttp.h"
|
||||
#include "ocrc.h"
|
||||
|
||||
static size_t WriteFileCallback(void*, size_t, size_t, void*);
|
||||
static size_t WriteMemoryCallback(void*, size_t, size_t, void*);
|
||||
|
||||
struct Fetchdata {
|
||||
FILE* stream;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
long
|
||||
ocfetchhttpcode(CURL* curl)
|
||||
{
|
||||
long httpcode;
|
||||
CURLcode cstat = CURLE_OK;
|
||||
/* Extract the http code */
|
||||
cstat = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&httpcode);
|
||||
if(cstat != CURLE_OK) httpcode = 0;
|
||||
return httpcode;
|
||||
}
|
||||
|
||||
int
|
||||
ocfetchurl_file(CURL* curl, const char* url, FILE* stream,
|
||||
off_t* sizep, long* filetime)
|
||||
{
|
||||
int stat = OC_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)
|
||||
goto fail;
|
||||
|
||||
if (stat == OC_NOERR) {
|
||||
/* return the file size*/
|
||||
#ifdef OCDEBUG
|
||||
oc_log(LOGNOTE,"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) goto fail;
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
|
||||
fail:
|
||||
oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
|
||||
return OCTHROW(OC_ECURL);
|
||||
}
|
||||
|
||||
int
|
||||
ocfetchurl(CURL* curl, const char* url, OCbytes* buf, long* filetime)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
CURLcode cstat = CURLE_OK;
|
||||
size_t len;
|
||||
|
||||
/* 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, WriteMemoryCallback);
|
||||
if (cstat != CURLE_OK)
|
||||
goto fail;
|
||||
|
||||
/* we pass our file to the callback function */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)buf);
|
||||
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);
|
||||
|
||||
cstat = curl_easy_perform(curl);
|
||||
if(cstat == CURLE_PARTIAL_FILE) {
|
||||
/* Log it but otherwise ignore */
|
||||
oc_log(LOGWARN, "curl error: %s; ignored",
|
||||
curl_easy_strerror(cstat));
|
||||
cstat = CURLE_OK;
|
||||
}
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
|
||||
/* Get the last modified time */
|
||||
if(filetime != NULL)
|
||||
cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
|
||||
/* Null terminate the buffer*/
|
||||
len = ocbyteslength(buf);
|
||||
ocbytesappend(buf, '\0');
|
||||
ocbytessetlength(buf, len); /* dont count null in buffer size*/
|
||||
#ifdef OCDEBUG
|
||||
oc_log(LOGNOTE,"buffersize: %lu bytes",(off_t)ocbyteslength(buf));
|
||||
#endif
|
||||
|
||||
return OCTHROW(stat);
|
||||
|
||||
fail:
|
||||
oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
|
||||
return OCTHROW(OC_ECURL);
|
||||
}
|
||||
|
||||
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)
|
||||
oc_log(LOGWARN,"WriteFileCallback: zero sized chunk");
|
||||
count = fwrite(ptr, size, nmemb, fetchdata->stream);
|
||||
if (count > 0) {
|
||||
fetchdata->size += (count * size);
|
||||
} else {
|
||||
oc_log(LOGWARN,"WriteFileCallback: zero sized write");
|
||||
}
|
||||
#ifdef OCPROGRESS
|
||||
oc_log(LOGNOTE,"callback: %lu bytes",(off_t)realsize);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t
|
||||
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
OCbytes* buf = (OCbytes*) data;
|
||||
if(realsize == 0)
|
||||
oc_log(LOGWARN,"WriteMemoryCallback: zero sized chunk");
|
||||
/* Optimize for reading potentially large dods datasets */
|
||||
if(!ocbytesavail(buf,realsize)) {
|
||||
/* double the size of the packet */
|
||||
ocbytessetalloc(buf,2*ocbytesalloc(buf));
|
||||
}
|
||||
ocbytesappendn(buf, ptr, realsize);
|
||||
#ifdef OCPROGRESS
|
||||
oc_log(LOGNOTE,"callback: %lu bytes",(off_t)realsize);
|
||||
#endif
|
||||
return realsize;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
assembleurl(DAPURL* durl, OCbytes* buf, int what)
|
||||
{
|
||||
encodeurltext(durl->url,buf);
|
||||
if(what & WITHPROJ) {
|
||||
ocbytescat(buf,"?");
|
||||
encodeurltext(durl->projection,buf);
|
||||
}
|
||||
if(what & WITHSEL) encodeurltext(durl->selection,buf);
|
||||
|
||||
}
|
||||
|
||||
static char mustencode="";
|
||||
static char hexchars[16] = {
|
||||
'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b',
|
||||
'c', 'd', 'e', 'f',
|
||||
};
|
||||
|
||||
static void
|
||||
encodeurltext(char* text, OCbytes* buf)
|
||||
{
|
||||
/* Encode the URL to handle illegal characters */
|
||||
len = strlen(url);
|
||||
encoded = ocmalloc(len*4+1); /* should never be larger than this*/
|
||||
if(encoded==NULL) return;
|
||||
p = url; q = encoded;
|
||||
while((c=*p++)) {
|
||||
if(strchr(mustencode,c) != NULL) {
|
||||
char tmp[8];
|
||||
int hex1, hex2;
|
||||
hex1 = (c & 0x0F);
|
||||
hex2 = (c & 0xF0) >> 4;
|
||||
tmp[0] = '0'; tmp[1] = 'x';
|
||||
tmp[2] = hexchars[hex2]; tmp[3] = hexchars[hex1];
|
||||
tmp[4] = '\0';
|
||||
ocbytescat(buf,tmp);
|
||||
} else *q++ = (char)c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
occurlopen(CURL** curlp)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
CURLcode cstat = CURLE_OK;
|
||||
CURL* curl;
|
||||
/* initialize curl*/
|
||||
curl = curl_easy_init();
|
||||
if (curl == NULL)
|
||||
stat = OC_ECURL;
|
||||
else {
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
||||
if (cstat != CURLE_OK)
|
||||
stat = OC_ECURL;
|
||||
/* some servers don't like requests that are made without a user-agent */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
||||
if (cstat != CURLE_OK)
|
||||
stat = OC_ECURL;
|
||||
}
|
||||
if (curlp)
|
||||
*curlp = curl;
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
void
|
||||
occurlclose(CURL* curl)
|
||||
{
|
||||
if (curl != NULL)
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
int
|
||||
ocfetchlastmodified(CURL* curl, char* url, long* filetime)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
CURLcode cstat = CURLE_OK;
|
||||
|
||||
/* Set the URL */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_URL, (void*)url);
|
||||
if (cstat != CURLE_OK)
|
||||
goto fail;
|
||||
|
||||
/* Ask for head */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30); /* 30sec timeout*/
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_HEADER, 1);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_FILETIME, (long)1);
|
||||
|
||||
cstat = curl_easy_perform(curl);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
if(filetime != NULL)
|
||||
cstat = curl_easy_getinfo(curl,CURLINFO_FILETIME,filetime);
|
||||
if(cstat != CURLE_OK) goto fail;
|
||||
|
||||
return OCTHROW(stat);
|
||||
|
||||
fail:
|
||||
oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
|
||||
return OCTHROW(OC_ECURL);
|
||||
}
|
||||
|
||||
int
|
||||
ocping(const char* url)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
CURLcode cstat = CURLE_OK;
|
||||
CURL* curl = NULL;
|
||||
OCbytes* buf = NULL;
|
||||
|
||||
/* Create a CURL instance */
|
||||
stat = occurlopen(&curl);
|
||||
if(stat != OC_NOERR) return stat;
|
||||
|
||||
/* use a very short timeout: 10 seconds */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)10);
|
||||
if (cstat != CURLE_OK)
|
||||
goto done;
|
||||
|
||||
/* fail on HTTP 400 code errors */
|
||||
cstat = curl_easy_setopt(curl, CURLOPT_FAILONERROR, (long)1);
|
||||
if (cstat != CURLE_OK)
|
||||
goto done;
|
||||
|
||||
/* Try to get the file */
|
||||
buf = ocbytesnew();
|
||||
stat = ocfetchurl(curl,url,buf,NULL);
|
||||
if(stat == OC_NOERR) {
|
||||
/* Don't trust curl to return an error when request gets 404 */
|
||||
long http_code = 0;
|
||||
cstat = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &http_code);
|
||||
if (cstat != CURLE_OK)
|
||||
goto done;
|
||||
if(http_code >= 400) {
|
||||
cstat = CURLE_HTTP_RETURNED_ERROR;
|
||||
goto done;
|
||||
}
|
||||
} else
|
||||
goto done;
|
||||
|
||||
done:
|
||||
ocbytesfree(buf);
|
||||
occurlclose(curl);
|
||||
if(cstat != CURLE_OK) {
|
||||
oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
|
||||
stat = OC_EDAPSVC;
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
|
22
oc2/ochttp.h
Normal file
22
oc2/ochttp.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H 1
|
||||
|
||||
extern int curlopen(CURL** curlp);
|
||||
extern void curlclose(CURL*);
|
||||
|
||||
extern int ocfetchurl(CURL*, const char*, OCbytes*, long*);
|
||||
extern int ocfetchurl_file(CURL*, const char*, FILE*, off_t*, long*);
|
||||
|
||||
extern long ocfetchhttpcode(CURL* curl);
|
||||
|
||||
extern int ocfetchlastmodified(CURL* curl, char* url, long* filetime);
|
||||
|
||||
extern int occurlopen(CURL** curlp);
|
||||
extern void occurlclose(CURL* curlp);
|
||||
|
||||
extern int ocping(const char* url);
|
||||
|
||||
#endif /*HTTP_H*/
|
551
oc2/ocinternal.c
Normal file
551
oc2/ocinternal.c
Normal file
@ -0,0 +1,551 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "occlientparams.h"
|
||||
#include "ocrc.h"
|
||||
#include "occurlfunctions.h"
|
||||
#include "ochttp.h"
|
||||
#include "ocread.h"
|
||||
#include "dapparselex.h"
|
||||
|
||||
/* Note: TMPPATH must end in '/' */
|
||||
#ifdef __CYGWIN__
|
||||
#define TMPPATH1 "c:/temp/"
|
||||
#define TMPPATH2 "./"
|
||||
#elif WIN32
|
||||
#define TMPPATH1 "c:\\temp\\"
|
||||
#define TMPPATH2 ".\\"
|
||||
#else
|
||||
#define TMPPATH1 "/tmp/"
|
||||
#define TMPPATH2 "./"
|
||||
#endif
|
||||
|
||||
/* Define default rc files and aliases*/
|
||||
static char* rcfilenames[4] = {".daprc",".dodsrc",".ocrc",NULL};
|
||||
|
||||
static int ocextractddsinmemory(OCstate*,OCtree*,int);
|
||||
static int ocextractddsinfile(OCstate*,OCtree*,int);
|
||||
static char* constraintescape(const char* url);
|
||||
static OCerror createtempfile(OCstate*,OCtree*);
|
||||
static int createtempfile1(char*,char**);
|
||||
|
||||
static void ocsetcurlproperties(OCstate*);
|
||||
|
||||
extern OCnode* makeunlimiteddimension(void);
|
||||
|
||||
#ifdef WIN32
|
||||
#include <fcntl.h>
|
||||
#define _S_IREAD 256
|
||||
#define _S_IWRITE 128
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/* Collect global state info in one place */
|
||||
struct OCGLOBALSTATE ocglobalstate;
|
||||
|
||||
int
|
||||
ocinternalinitialize(void)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
|
||||
if(!ocglobalstate.initialized) {
|
||||
memset((void*)&ocglobalstate,0,sizeof(ocglobalstate));
|
||||
ocglobalstate.initialized = 1;
|
||||
}
|
||||
|
||||
/* Compute some xdr related flags */
|
||||
xxdr_init();
|
||||
|
||||
oc_loginit();
|
||||
|
||||
oc_curl_protocols(&ocglobalstate); /* see what protocols are supported */
|
||||
|
||||
/* compile the .dodsrc, if any */
|
||||
{
|
||||
char* path = NULL;
|
||||
char* homepath = NULL;
|
||||
char** alias;
|
||||
FILE* f = NULL;
|
||||
/* locate the configuration files: . first in '.', then $HOME */
|
||||
for(alias=rcfilenames;*alias;alias++) {
|
||||
path = (char*)malloc(strlen("./")+strlen(*alias)+1);
|
||||
if(path == NULL) return OC_ENOMEM;
|
||||
strcpy(path,"./");
|
||||
strcat(path,*alias);
|
||||
/* see if file is readable */
|
||||
f = fopen(path,"r");
|
||||
if(f != NULL) break;
|
||||
if(path != NULL) {free(path); path = NULL;} /* cleanup */
|
||||
}
|
||||
if(f == NULL) { /* try $HOME */
|
||||
OCASSERT(path == NULL);
|
||||
homepath = getenv("HOME");
|
||||
if (homepath!= NULL) {
|
||||
for(alias=rcfilenames;*alias;alias++) {
|
||||
path = (char*)malloc(strlen(homepath)+1+strlen(*alias)+1);
|
||||
if(path == NULL) return OC_ENOMEM;
|
||||
strcpy(path,homepath);
|
||||
strcat(path,"/");
|
||||
strcat(path,*alias);
|
||||
f = fopen(path,"r");
|
||||
if(f != NULL) break;
|
||||
if(path != NULL) {free(path); path=NULL;}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(f == NULL) {
|
||||
oc_log(LOGDBG,"Cannot find runtime configuration file");
|
||||
} else {
|
||||
OCASSERT(path != NULL);
|
||||
fclose(f);
|
||||
if(ocdebug > 1)
|
||||
fprintf(stderr, "DODS RC file: %s\n", path);
|
||||
if(ocdodsrc_read(*alias,path) == 0)
|
||||
oc_log(LOGERR, "Error parsing %s\n",path);
|
||||
}
|
||||
if(path != NULL) free(path);
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
OCerror
|
||||
ocopen(OCstate** statep, const char* url)
|
||||
{
|
||||
int stat = OC_NOERR;
|
||||
OCstate * state = NULL;
|
||||
OCURI* tmpurl = NULL;
|
||||
CURL* curl = NULL; /* curl handle*/
|
||||
|
||||
if(!ocuriparse(url,&tmpurl)) {OCTHROWCHK(stat=OC_EBADURL); goto fail;}
|
||||
|
||||
stat = occurlopen(&curl);
|
||||
if(stat != OC_NOERR) {OCTHROWCHK(stat); goto fail;}
|
||||
|
||||
state = (OCstate*)ocmalloc(sizeof(OCstate)); /* ocmalloc zeros memory*/
|
||||
if(state == NULL) {OCTHROWCHK(stat=OC_ENOMEM); goto fail;}
|
||||
|
||||
/* Setup DAP state*/
|
||||
state->header.magic = OCMAGIC;
|
||||
state->header.occlass = OC_State;
|
||||
state->curl = curl;
|
||||
state->trees = oclistnew();
|
||||
state->uri = tmpurl;
|
||||
if(!ocuridecodeparams(state->uri)) {
|
||||
oc_log(LOGWARN,"Could not parse client parameters");
|
||||
}
|
||||
state->packet = ocbytesnew();
|
||||
ocbytessetalloc(state->packet,DFALTPACKETSIZE); /*initial reasonable size*/
|
||||
|
||||
/* set curl properties for this link */
|
||||
ocsetcurlproperties(state);
|
||||
|
||||
if(statep) *statep = state;
|
||||
return OCTHROW(stat);
|
||||
|
||||
fail:
|
||||
ocurifree(tmpurl);
|
||||
if(state != NULL) ocfree(state);
|
||||
if(curl != NULL) occurlclose(curl);
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocfetch(OCstate* state, const char* constraint, OCdxd kind, OCflags flags,
|
||||
OCnode** rootp)
|
||||
{
|
||||
OCtree* tree = NULL;
|
||||
OCnode* root = NULL;
|
||||
OCerror stat = OC_NOERR;
|
||||
|
||||
tree = (OCtree*)ocmalloc(sizeof(OCtree));
|
||||
MEMCHECK(tree,OC_ENOMEM);
|
||||
memset((void*)tree,0,sizeof(OCtree));
|
||||
tree->dxdclass = kind;
|
||||
tree->state = state;
|
||||
tree->constraint = constraintescape(constraint);
|
||||
if(tree->constraint == NULL)
|
||||
tree->constraint = nulldup(constraint);
|
||||
|
||||
/* Set curl properties: pwd, flags, proxies, ssl */
|
||||
if((stat=ocset_user_password(state))!= OC_NOERR) goto fail;
|
||||
if((stat=ocset_curl_flags(state)) != OC_NOERR) goto fail;
|
||||
if((stat=ocset_proxy(state)) != OC_NOERR) goto fail;
|
||||
if((stat=ocset_ssl(state)) != OC_NOERR) goto fail;
|
||||
|
||||
ocbytesclear(state->packet);
|
||||
|
||||
switch (kind) {
|
||||
case OCDAS:
|
||||
stat = readDAS(state,tree);
|
||||
if(stat == OC_NOERR) {
|
||||
tree->text = ocbytesdup(state->packet);
|
||||
if(tree->text == NULL) stat = OC_EDAS;
|
||||
}
|
||||
break;
|
||||
case OCDDS:
|
||||
stat = readDDS(state,tree);
|
||||
if(stat == OC_NOERR) {
|
||||
tree->text = ocbytesdup(state->packet);
|
||||
if(tree->text == NULL) stat = OC_EDDS;
|
||||
}
|
||||
break;
|
||||
case OCDATADDS:
|
||||
if((flags & OCONDISK) != 0) {/* store in file */
|
||||
/* Create the datadds file immediately
|
||||
so that DRNO can reference it*/
|
||||
/* Make the tmp file*/
|
||||
stat = createtempfile(state,tree);
|
||||
if(stat) {OCTHROWCHK(stat); goto unwind;}
|
||||
stat = readDATADDS(state,tree,flags);
|
||||
if(stat == OC_NOERR) {
|
||||
/* Separate the DDS from data and return the dds;
|
||||
will modify packet */
|
||||
stat = ocextractddsinfile(state,tree,flags);
|
||||
}
|
||||
} else { /*inmemory*/
|
||||
stat = readDATADDS(state,tree,flags);
|
||||
if(stat == OC_NOERR) {
|
||||
/* Separate the DDS from data and return the dds;
|
||||
will modify packet */
|
||||
stat = ocextractddsinmemory(state,tree,flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}/*switch*/
|
||||
if(stat != OC_NOERR) {
|
||||
/* Obtain any http code */
|
||||
state->error.httpcode = ocfetchhttpcode(state->curl);
|
||||
if(state->error.httpcode >= 400) {
|
||||
oc_log(LOGWARN,"oc_open: Could not read url; http error = %l",state->error.httpcode);
|
||||
} else {
|
||||
oc_log(LOGWARN,"oc_open: Could not read url");
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
tree->nodes = NULL;
|
||||
stat = DAPparse(state,tree,tree->text);
|
||||
/* Check and report on an error return from the server */
|
||||
if(stat == OC_EDAPSVC && state->error.code != NULL) {
|
||||
oc_log(LOGERR,"oc_open: server error retrieving url: code=%s message=\"%s\"",
|
||||
state->error.code,
|
||||
(state->error.message?state->error.message:""));
|
||||
}
|
||||
if(stat) {OCTHROWCHK(stat); goto unwind;}
|
||||
root = tree->root;
|
||||
/* make sure */
|
||||
tree->root = root;
|
||||
root->tree = tree;
|
||||
|
||||
/* Verify the parse */
|
||||
switch (kind) {
|
||||
case OCDAS:
|
||||
if(root->octype != OC_Attributeset)
|
||||
{OCTHROWCHK(stat=OC_EDAS); goto unwind;}
|
||||
break;
|
||||
case OCDDS:
|
||||
if(root->octype != OC_Dataset)
|
||||
{OCTHROWCHK(stat=OC_EDDS); goto unwind;}
|
||||
break;
|
||||
case OCDATADDS:
|
||||
if(root->octype != OC_Dataset)
|
||||
{OCTHROWCHK(stat=OC_EDATADDS); goto unwind;}
|
||||
/* Modify the tree kind */
|
||||
tree->dxdclass = OCDATADDS;
|
||||
break;
|
||||
default: return OC_EINVAL;
|
||||
}
|
||||
|
||||
if(kind != OCDAS) {
|
||||
/* Process ocnodes to mark those that are cacheable */
|
||||
ocmarkcacheable(state,root);
|
||||
/* Process ocnodes to handle various semantic issues*/
|
||||
occomputesemantics(tree->nodes);
|
||||
}
|
||||
|
||||
/* Process ocnodes to compute name info*/
|
||||
occomputefullnames(tree->root);
|
||||
|
||||
if(kind == OCDATADDS) {
|
||||
if((flags & OCONDISK) != 0) {
|
||||
tree->data.xdrs = xxdr_filecreate(tree->data.file,tree->data.bod);
|
||||
} else {
|
||||
/* Switch to zero based memory */
|
||||
tree->data.xdrs
|
||||
= xxdr_memcreate(tree->data.memory,tree->data.datasize,tree->data.bod);
|
||||
}
|
||||
MEMCHECK(tree->data.xdrs,OC_ENOMEM);
|
||||
/* Compile the data into a more accessible format */
|
||||
stat = occompile(state,tree->root);
|
||||
if(stat != OC_NOERR)
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* Put root into the state->trees list */
|
||||
oclistpush(state->trees,(ocelem)root);
|
||||
|
||||
if(rootp) *rootp = root;
|
||||
return stat;
|
||||
|
||||
unwind:
|
||||
octree_free(tree);
|
||||
fail:
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
createtempfile(OCstate* state, OCtree* tree)
|
||||
{
|
||||
int fd;
|
||||
char* name = NULL;
|
||||
fd = createtempfile1(TMPPATH1,&name);
|
||||
if(fd < 0)
|
||||
fd = createtempfile1(TMPPATH2,&name);
|
||||
if(fd < 0) {
|
||||
oc_log(LOGERR,"oc_open: attempt to open tmp file failed: %s",name);
|
||||
return errno;
|
||||
}
|
||||
#ifdef OCDEBUG
|
||||
oc_log(LOGNOTE,"oc_open: using tmp file: %s",name);
|
||||
#endif
|
||||
tree->data.filename = name; /* remember our tmp file name */
|
||||
tree->data.file = fdopen(fd,"w+");
|
||||
if(tree->data.file == NULL) return OC_EOPEN;
|
||||
/* unlink the temp file so it will automatically be reclaimed */
|
||||
if(ocdebug == 0) unlink(tree->data.filename);
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
int
|
||||
createtempfile1(char* tmppath, char** tmpnamep)
|
||||
{
|
||||
int fd;
|
||||
char* tmpname = NULL;
|
||||
tmpname = (char*)malloc(strlen(tmppath)+strlen("dataddsXXXXXX")+1);
|
||||
if(tmpname == NULL) return -1;
|
||||
strcpy(tmpname,tmppath);
|
||||
#ifdef HAVE_MKSTEMP
|
||||
strcat(tmpname,"dataddsXXXXXX");
|
||||
/* Note Potential problem: old versions of this function
|
||||
leave the file in mode 0666 instead of 0600 */
|
||||
fd = mkstemp(tmpname);
|
||||
#else /* !HAVE_MKSTEMP */
|
||||
/* Need to simulate by using some kind of pseudo-random number */
|
||||
strcat(tmpname,"datadds");
|
||||
{
|
||||
int rno = rand();
|
||||
char spid[7];
|
||||
if(rno < 0) rno = -rno;
|
||||
sprintf(spid,"%06d",rno);
|
||||
strcat(tmpname,spid);
|
||||
# ifdef WIN32
|
||||
fd=open(tmpname,O_RDWR|O_BINARY|O_CREAT|O_EXCL|_O_SHORT_LIVED, _S_IREAD|_S_IWRITE);
|
||||
# else
|
||||
fd=open(tmpname,O_RDWR|O_CREAT|O_EXCL, S_IRWXU);
|
||||
# endif
|
||||
}
|
||||
#endif /* !HAVE_MKSTEMP */
|
||||
if(tmpname == NULL) return -1;
|
||||
if(tmpnamep) *tmpnamep = tmpname;
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
occlose(OCstate* state)
|
||||
{
|
||||
unsigned int i;
|
||||
if(state == NULL) return;
|
||||
|
||||
/* Warning: ocfreeroot will attempt to remove the root from state->trees */
|
||||
/* Ok in this case because we are popping the root out of state->trees */
|
||||
for(i=0;i<oclistlength(state->trees);i++) {
|
||||
OCnode* root = (OCnode*)oclistpop(state->trees);
|
||||
ocroot_free(root);
|
||||
}
|
||||
oclistfree(state->trees);
|
||||
ocurifree(state->uri);
|
||||
ocbytesfree(state->packet);
|
||||
ocfree(state->error.code);
|
||||
ocfree(state->error.message);
|
||||
ocfree(state->curlflags.useragent);
|
||||
ocfree(state->curlflags.cookiejar);
|
||||
ocfree(state->curlflags.cookiefile);
|
||||
ocfree(state->ssl.certificate);
|
||||
ocfree(state->ssl.key);
|
||||
ocfree(state->ssl.keypasswd);
|
||||
ocfree(state->ssl.cainfo);
|
||||
ocfree(state->ssl.capath);
|
||||
ocfree(state->proxy.host);
|
||||
ocfree(state->creds.username);
|
||||
ocfree(state->creds.password);
|
||||
if(state->curl != NULL) occurlclose(state->curl);
|
||||
ocfree(state);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
ocextractddsinmemory(OCstate* state, OCtree* tree, OCflags flags)
|
||||
{
|
||||
OCerror stat = OC_NOERR;
|
||||
size_t ddslen, bod, bodfound;
|
||||
/* Read until we find the separator (or EOF)*/
|
||||
bodfound = ocfindbod(state->packet,&bod,&ddslen);
|
||||
if(!bodfound) {/* No BOD; pretend */
|
||||
bod = tree->data.bod;
|
||||
ddslen = tree->data.datasize;
|
||||
}
|
||||
tree->data.bod = bod;
|
||||
tree->data.ddslen = ddslen;
|
||||
/* copy out the dds */
|
||||
if(ddslen > 0) {
|
||||
tree->text = (char*)ocmalloc(ddslen+1);
|
||||
memcpy((void*)tree->text,(void*)ocbytescontents(state->packet),ddslen);
|
||||
tree->text[ddslen] = '\0';
|
||||
} else
|
||||
tree->text = NULL;
|
||||
/* Extract the inmemory contents */
|
||||
tree->data.memory = ocbytesextract(state->packet);
|
||||
#ifdef OCIGNORE
|
||||
/* guarantee the data part is on an 8 byte boundary */
|
||||
if(tree->data.bod % 8 != 0) {
|
||||
unsigned long count = tree->data.datasize - tree->data.bod;
|
||||
memcpy(tree->xdrmemory,tree->xdrmemory+tree->data.bod,count);
|
||||
tree->data.datasize = count;
|
||||
tree->data.bod = 0;
|
||||
tree->data.ddslen = 0;
|
||||
}
|
||||
#endif
|
||||
if(tree->text == NULL) stat = OC_EDATADDS;
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
static OCerror
|
||||
ocextractddsinfile(OCstate* state, OCtree* tree, OCflags flags)
|
||||
{
|
||||
OCerror stat = OC_NOERR;
|
||||
size_t ddslen, bod, bodfound;
|
||||
|
||||
/* Read until we find the separator (or EOF)*/
|
||||
ocbytesclear(state->packet);
|
||||
rewind(tree->data.file);
|
||||
bodfound = 0;
|
||||
do {
|
||||
char chunk[1024];
|
||||
size_t count;
|
||||
/* read chunks of the file until we find the separator*/
|
||||
count = fread(chunk,1,sizeof(chunk),tree->data.file);
|
||||
if(count <= 0) break; /* EOF;*/
|
||||
ocbytesappendn(state->packet,chunk,count);
|
||||
bodfound = ocfindbod(state->packet,&bod,&ddslen);
|
||||
} while(!bodfound);
|
||||
if(!bodfound) {/* No BOD; pretend */
|
||||
bod = tree->data.bod;
|
||||
ddslen = tree->data.datasize;
|
||||
}
|
||||
tree->data.bod = bod;
|
||||
tree->data.ddslen = ddslen;
|
||||
/* copy out the dds */
|
||||
if(ddslen > 0) {
|
||||
tree->text = (char*)ocmalloc(ddslen+1);
|
||||
memcpy((void*)tree->text,(void*)ocbytescontents(state->packet),ddslen);
|
||||
tree->text[ddslen] = '\0';
|
||||
} else
|
||||
tree->text = NULL;
|
||||
/* reset the position of the tmp file*/
|
||||
fseek(tree->data.file,tree->data.bod,SEEK_SET);
|
||||
if(tree->text == NULL) stat = OC_EDATADDS;
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
/* Allow these (non-alpha-numerics) to pass thru */
|
||||
static char okchars[] = "&/:;,.=?@'\"<>{}!|\\^[]`~";
|
||||
static char hexdigits[] = "0123456789abcdef";
|
||||
|
||||
/* Modify constraint to use %XX escapes */
|
||||
static char*
|
||||
constraintescape(const char* url)
|
||||
{
|
||||
size_t len;
|
||||
char* p;
|
||||
int c;
|
||||
char* eurl;
|
||||
|
||||
if(url == NULL) return NULL;
|
||||
len = strlen(url);
|
||||
eurl = ocmalloc(1+3*len); /* worst case: c -> %xx */
|
||||
MEMCHECK(eurl,NULL);
|
||||
p = eurl;
|
||||
*p = '\0';
|
||||
while((c=*url++)) {
|
||||
if(c >= '0' && c <= '9') {*p++ = c;}
|
||||
else if(c >= 'a' && c <= 'z') {*p++ = c;}
|
||||
else if(c >= 'A' && c <= 'Z') {*p++ = c;}
|
||||
else if(strchr(okchars,c) != NULL) {*p++ = c;}
|
||||
else {
|
||||
*p++ = '%';
|
||||
*p++ = hexdigits[(c & 0xf0)>>4];
|
||||
*p++ = hexdigits[(c & 0xf)];
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return eurl;
|
||||
}
|
||||
|
||||
OCerror
|
||||
ocupdatelastmodifieddata(OCstate* state)
|
||||
{
|
||||
OCerror status = OC_NOERR;
|
||||
long lastmodified;
|
||||
char* base = NULL;
|
||||
base = ocuribuild(state->uri,NULL,NULL,OCURIENCODE);
|
||||
status = ocfetchlastmodified(state->curl, base, &lastmodified);
|
||||
free(base);
|
||||
if(status == OC_NOERR) {
|
||||
state->datalastmodified = lastmodified;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Set curl properties for link based on rc files
|
||||
*/
|
||||
static void
|
||||
ocsetcurlproperties(OCstate* state)
|
||||
{
|
||||
CURLcode cstat = CURLE_OK;
|
||||
|
||||
/* process the triple store wrt to this state */
|
||||
if(ocdodsrc_process(state) != OC_NOERR) {
|
||||
oc_log(LOGERR,"Malformed .opendaprc configuration file");
|
||||
goto fail;
|
||||
}
|
||||
if(state->creds.username == NULL && state->creds.password == NULL) {
|
||||
if(state->uri->user != NULL && state->uri->password != NULL) {
|
||||
/* this overrides .dodsrc */
|
||||
if(state->creds.password) free(state->creds.password);
|
||||
state->creds.password = nulldup(state->uri->password);
|
||||
if(state->creds.username) free(state->creds.username);
|
||||
state->creds.username = nulldup(state->uri->user);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
if(cstat != CURLE_OK)
|
||||
oc_log(LOGERR, "curl error: %s", curl_easy_strerror(cstat));
|
||||
return;
|
||||
}
|
201
oc2/ocinternal.h
Normal file
201
oc2/ocinternal.h
Normal file
@ -0,0 +1,201 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCINTERNAL_H
|
||||
#define OCINTERNAL_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _AIX
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#define CURL_DISABLE_TYPECHECK 1
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "oclist.h"
|
||||
#include "ocbytes.h"
|
||||
#include "ocuri.h"
|
||||
|
||||
#define OCCACHEPOS
|
||||
|
||||
/* Forwards */
|
||||
typedef struct OCstate OCstate;
|
||||
typedef struct OCnode OCnode;
|
||||
typedef struct OCdata OCdata;
|
||||
struct OCTriplestore;
|
||||
|
||||
/* Define the internal node classification values */
|
||||
#define OC_None 0
|
||||
#define OC_State 1
|
||||
#define OC_Node 2
|
||||
#define OC_Data 3
|
||||
|
||||
/* Define a magic number to mark externally visible oc objects */
|
||||
#define OCMAGIC ((unsigned int)0x0c0c0c0c) /*clever, huh*/
|
||||
|
||||
/* Define a struct that all oc objects must start with */
|
||||
/* OCheader must be defined here to make it available in other headers */
|
||||
typedef struct OCheader {
|
||||
unsigned int magic;
|
||||
unsigned int occlass;
|
||||
} OCheader;
|
||||
|
||||
#include "oc.h"
|
||||
#include "ocx.h"
|
||||
#include "ocnode.h"
|
||||
#include "ocdata.h"
|
||||
#include "occonstraints.h"
|
||||
#include "ocutil.h"
|
||||
#include "oclog.h"
|
||||
#include "xxdr.h"
|
||||
#include "ocdatatypes.h"
|
||||
#include "occompile.h"
|
||||
|
||||
#ifndef nulldup
|
||||
#define nulldup(s) (s==NULL?NULL:strdup(s))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros for dealing with flag bits.
|
||||
*/
|
||||
#define fset(t,f) ((t) |= (f))
|
||||
#define fclr(t,f) ((t) &= ~(f))
|
||||
#define fisset(t,f) ((t) & (f))
|
||||
|
||||
#define nullstring(s) (s==NULL?"(null)":s)
|
||||
#define PATHSEPARATOR "."
|
||||
|
||||
/* Define infinity for memory size */
|
||||
#if SIZEOF_SIZE_T == 4
|
||||
#define OCINFINITY ((size_t)0xffffffff)
|
||||
#else
|
||||
#define OCINFINITY ((size_t)0xffffffffffffffff)
|
||||
#endif
|
||||
|
||||
/* Extend the OCdxd type for internal use */
|
||||
#define OCVER 3
|
||||
|
||||
/* Default initial memory packet size */
|
||||
#define DFALTPACKETSIZE 0x20000 /*approximately 100k bytes*/
|
||||
|
||||
/* Default maximum memory packet size */
|
||||
#define DFALTMAXPACKETSIZE 0x3000000 /*approximately 50M bytes*/
|
||||
|
||||
/* Collect global state info in one place */
|
||||
extern struct OCGLOBALSTATE {
|
||||
int initialized;
|
||||
struct {
|
||||
int proto_file;
|
||||
int proto_https;
|
||||
} curl;
|
||||
struct OCTriplestore* ocdodsrc; /* the .dodsrc triple store */
|
||||
} ocglobalstate;
|
||||
|
||||
/*! Specifies the OCstate = non-opaque version of OClink */
|
||||
struct OCstate {
|
||||
OCheader header; /* class=OC_State */
|
||||
OClist* trees; /* list<OCNODE*> ; all root objects */
|
||||
OCURI* uri; /* base URI*/
|
||||
OCbytes* packet; /* shared by all trees during construction */
|
||||
struct OCerrdata {/* Hold info for an error return from server */
|
||||
char* code;
|
||||
char* message;
|
||||
long httpcode;
|
||||
char curlerrorbuf[CURL_ERROR_SIZE]; /* to get curl error message */
|
||||
} error;
|
||||
CURL* curl; /* curl handle*/
|
||||
char curlerror[CURL_ERROR_SIZE];
|
||||
struct OCcurlflags {
|
||||
int proto_file;
|
||||
int proto_https;
|
||||
int compress;
|
||||
int verbose;
|
||||
int timeout;
|
||||
int followlocation;
|
||||
int maxredirs;
|
||||
char* useragent;
|
||||
char* cookiejar;
|
||||
char* cookiefile;
|
||||
} curlflags;
|
||||
struct OCSSL {
|
||||
int validate;
|
||||
char* certificate;
|
||||
char* key;
|
||||
char* keypasswd;
|
||||
char* cainfo; /* certificate authority */
|
||||
char* capath;
|
||||
int verifypeer;
|
||||
} ssl;
|
||||
struct OCproxy {
|
||||
char *host;
|
||||
int port;
|
||||
} proxy;
|
||||
struct OCcredentials {
|
||||
char *username;
|
||||
char *password;
|
||||
} creds;
|
||||
long ddslastmodified;
|
||||
long datalastmodified;
|
||||
};
|
||||
|
||||
/*! OCtree holds extra state info about trees */
|
||||
|
||||
typedef struct OCtree
|
||||
{
|
||||
OCdxd dxdclass;
|
||||
char* constraint;
|
||||
char* text;
|
||||
struct OCnode* root; /* cross link */
|
||||
struct OCstate* state; /* cross link */
|
||||
OClist* nodes; /* all nodes in tree*/
|
||||
/* when dxdclass == OCDATADDS */
|
||||
struct {
|
||||
char* memory; /* allocated memory if OC_ONDISK is not set */
|
||||
char* filename; /* If OC_ONDISK is set */
|
||||
FILE* file;
|
||||
off_t datasize; /* xdr size on disk or in memory */
|
||||
off_t bod; /* offset of the beginning of packet data */
|
||||
off_t ddslen; /* length of ddslen (assert(ddslen <= bod)) */
|
||||
XXDR* xdrs; /* access either memory or file */
|
||||
OCdata* data;
|
||||
} data;
|
||||
} OCtree;
|
||||
|
||||
/* (Almost) All shared procedure definitions are kept here
|
||||
except for: ocdebug.h ocutil.h
|
||||
The true external interface is defined in oc.h
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* Location: ceparselex.c*/
|
||||
extern int cedebug;
|
||||
extern OClist* CEparse(OCstate*,char* input);
|
||||
#endif
|
||||
|
||||
extern OCerror ocopen(OCstate** statep, const char* url);
|
||||
extern void occlose(OCstate* state);
|
||||
extern OCerror ocfetch(OCstate*, const char*, OCdxd, OCflags, OCnode**);
|
||||
extern int oc_network_order;
|
||||
extern int oc_invert_xdr_double;
|
||||
extern int ocinternalinitialize(void);
|
||||
|
||||
extern OCerror ocupdatelastmodifieddata(OCstate* state);
|
||||
|
||||
extern int ocinternalinitialize(void);
|
||||
|
||||
#endif /*COMMON_H*/
|
171
oc2/oclist.c
Normal file
171
oc2/oclist.c
Normal file
@ -0,0 +1,171 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "oclist.h"
|
||||
|
||||
static ocelem ocDATANULL = (ocelem)0;
|
||||
/*static int ocinitialized=0;*/
|
||||
|
||||
int oclistnull(ocelem e) {return e == ocDATANULL;}
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define DEFAULTALLOC 16
|
||||
#define ALLOCINCR 16
|
||||
|
||||
OClist* oclistnewn(int prealloc)
|
||||
{
|
||||
OClist* l;
|
||||
/*
|
||||
if(!ocinitialized) {
|
||||
memset((void*)&ocDATANULL,0,sizeof(ocelem));
|
||||
ocinitialized = 1;
|
||||
}
|
||||
*/
|
||||
if(prealloc < 0) prealloc = 0;
|
||||
l = (OClist*)malloc(sizeof(OClist));
|
||||
if(l) {
|
||||
l->alloc=prealloc;
|
||||
l->length=prealloc;
|
||||
l->content=(prealloc==0?NULL:(ocelem*)calloc(prealloc,sizeof(ocelem)));
|
||||
if(l == NULL) {free(l);return 0;}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
oclistfree(OClist* l)
|
||||
{
|
||||
if(l) {
|
||||
l->alloc = 0;
|
||||
if(l->content != NULL) {free(l->content); l->content = NULL;}
|
||||
free(l);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
oclistsetalloc(OClist* l, unsigned int sz)
|
||||
{
|
||||
ocelem* newcontent;
|
||||
if(l == NULL) return FALSE;
|
||||
if(sz <= 0) {sz = (l->length?2*l->length:DEFAULTALLOC);}
|
||||
if(l->alloc >= sz) {return TRUE;}
|
||||
newcontent=(ocelem*)calloc(sz,sizeof(ocelem));
|
||||
if(l->alloc > 0 && l->length > 0 && l->content != NULL) {
|
||||
memcpy((void*)newcontent,(void*)l->content,sizeof(ocelem)*l->length);
|
||||
free(l->content);
|
||||
}
|
||||
l->content=newcontent;
|
||||
l->alloc=sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
oclistsetlength(OClist* l, unsigned int sz)
|
||||
{
|
||||
if(l == NULL) return FALSE;
|
||||
if(sz > l->alloc && !oclistsetalloc(l,sz)) return FALSE;
|
||||
l->length = sz;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ocelem
|
||||
oclistget(OClist* l, unsigned int index)
|
||||
{
|
||||
if(l == NULL || l->length == 0) return ocDATANULL;
|
||||
if(index >= l->length) return ocDATANULL;
|
||||
return l->content[index];
|
||||
}
|
||||
|
||||
int
|
||||
oclistset(OClist* l, unsigned int index, ocelem elem)
|
||||
{
|
||||
if(l == NULL) return FALSE;
|
||||
if(index >= l->length) return FALSE;
|
||||
l->content[index] = elem;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Insert at position i of l; will push up elements i..|seq|. */
|
||||
int
|
||||
oclistinsert(OClist* l, unsigned int index, ocelem elem)
|
||||
{
|
||||
unsigned int i;
|
||||
if(l == NULL) return FALSE;
|
||||
if(index > l->length) return FALSE;
|
||||
oclistsetalloc(l,0);
|
||||
for(i=l->length;i>index;i--) l->content[i] = l->content[i-1];
|
||||
l->content[index] = elem;
|
||||
l->length++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
oclistpush(OClist* l, ocelem elem)
|
||||
{
|
||||
if(l == NULL) return FALSE;
|
||||
if(l->length >= l->alloc) oclistsetalloc(l,0);
|
||||
l->content[l->length] = elem;
|
||||
l->length++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ocelem
|
||||
oclistpop(OClist* l)
|
||||
{
|
||||
if(l == NULL || l->length == 0) return ocDATANULL;
|
||||
l->length--;
|
||||
return l->content[l->length];
|
||||
}
|
||||
|
||||
ocelem
|
||||
oclisttop(OClist* l)
|
||||
{
|
||||
if(l == NULL || l->length == 0) return ocDATANULL;
|
||||
return l->content[l->length - 1];
|
||||
}
|
||||
|
||||
ocelem
|
||||
oclistremove(OClist* l, unsigned int i)
|
||||
{
|
||||
unsigned int len;
|
||||
ocelem elem;
|
||||
if(l == NULL || (len=l->length) == 0) return ocDATANULL;
|
||||
if(i >= len) return ocDATANULL;
|
||||
elem = l->content[i];
|
||||
for(i++;i<len;i++) l->content[i-1] = l->content[i];
|
||||
l->length--;
|
||||
return elem;
|
||||
}
|
||||
|
||||
/* Duplicate and return the content (null terminate) */
|
||||
ocelem*
|
||||
oclistdup(OClist* l)
|
||||
{
|
||||
ocelem* result = (ocelem*)malloc(sizeof(ocelem)*(l->length+1));
|
||||
memcpy((void*)result,(void*)l->content,sizeof(ocelem)*l->length);
|
||||
result[l->length] = (ocelem)0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
oclistcontains(OClist* list, ocelem elem)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<oclistlength(list);i++) {
|
||||
if(elem == oclistget(list,i)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
57
oc2/oclist.h
Normal file
57
oc2/oclist.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
#ifndef OCLIST_H
|
||||
#define OCLIST_H 1
|
||||
|
||||
/* Define the type of the elements in the list*/
|
||||
|
||||
#if defined(_CPLUSPLUS_) || defined(__CPLUSPLUS__)
|
||||
#define EXTERNC extern "C"
|
||||
#else
|
||||
#define EXTERNC extern
|
||||
#endif
|
||||
|
||||
typedef unsigned long ocelem;
|
||||
|
||||
EXTERNC int oclistnull(ocelem);
|
||||
|
||||
typedef struct OClist {
|
||||
unsigned int alloc;
|
||||
unsigned int length;
|
||||
ocelem* content;
|
||||
} OClist;
|
||||
|
||||
EXTERNC OClist* oclistnewn(int);
|
||||
EXTERNC int oclistfree(OClist*);
|
||||
EXTERNC int oclistsetalloc(OClist*,unsigned int);
|
||||
EXTERNC int oclistsetlength(OClist*,unsigned int);
|
||||
|
||||
/* Set the ith element */
|
||||
EXTERNC int oclistset(OClist*,unsigned int,ocelem);
|
||||
/* Get value at position i */
|
||||
EXTERNC ocelem oclistget(OClist*,unsigned int);/* Return the ith element of l */
|
||||
/* Insert at position i; will push up elements i..|seq|. */
|
||||
EXTERNC int oclistinsert(OClist*,unsigned int,ocelem);
|
||||
/* Remove element at position i; will move higher elements down */
|
||||
EXTERNC ocelem oclistremove(OClist* l, unsigned int i);
|
||||
|
||||
/* Tail operations */
|
||||
EXTERNC int oclistpush(OClist*,ocelem); /* Add at Tail */
|
||||
EXTERNC ocelem oclistpop(OClist*);
|
||||
EXTERNC ocelem oclisttop(OClist*);
|
||||
|
||||
/* Duplicate and return the content (null terminate) */
|
||||
EXTERNC ocelem* oclistdup(OClist*);
|
||||
|
||||
/* Look for value match */
|
||||
EXTERNC int oclistcontains(OClist*, ocelem);
|
||||
|
||||
/* Following are always "in-lined"*/
|
||||
#define oclistnew() oclistnewn(0)
|
||||
#define oclistclear(l) oclistsetlength((l),0U)
|
||||
#define oclistextend(l,len) oclistsetalloc((l),(len)+(l->alloc))
|
||||
#define oclistcontents(l) ((l)->content)
|
||||
#define oclistlength(l) ((l)?(l)->length:0U)
|
||||
|
||||
#endif /*OCLIST_H*/
|
||||
|
184
oc2/oclog.c
Normal file
184
oc2/oclog.c
Normal file
@ -0,0 +1,184 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ocinternal.h"
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define PREFIXLEN 8
|
||||
|
||||
#define ENVFLAG "OCLOGFILE"
|
||||
|
||||
static int ocloginit = 0;
|
||||
static int oclogging = 0;
|
||||
static int ocsystemfile = 0; /* 1 => we are logging something we did not open */
|
||||
static char* oclogfile = NULL;
|
||||
static FILE* oclogstream = NULL;
|
||||
|
||||
/*!\defgroup OClog OClog Management
|
||||
@{*/
|
||||
|
||||
/*!\internal
|
||||
*/
|
||||
|
||||
void
|
||||
oc_loginit(void)
|
||||
{
|
||||
const char* file = getenv(ENVFLAG); /* I hope this is portable*/
|
||||
ocloginit = 1;
|
||||
oc_setlogging(0);
|
||||
oclogfile = NULL;
|
||||
oclogstream = NULL;
|
||||
/* Use environment variables to preset oclogging state*/
|
||||
if(file != NULL) {
|
||||
oc_setlogging(1);
|
||||
oc_logopen(file);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Enable/Disable logging.
|
||||
|
||||
\param[in] tf If 1, then turn on logging, if 0, then turn off logging.
|
||||
|
||||
\return The previous value of the logging flag.
|
||||
*/
|
||||
|
||||
int
|
||||
oc_setlogging(int tf)
|
||||
{
|
||||
int was;
|
||||
if(!ocloginit) oc_loginit();
|
||||
was = oclogging;
|
||||
oclogging = tf;
|
||||
return was;
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify a file into which to place logging output.
|
||||
|
||||
\param[in] file The name of the file into which to place logging output.
|
||||
If the file has the value NULL, then send logging output to
|
||||
stderr.
|
||||
|
||||
\return zero if the open failed, one otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
oc_logopen(const char* file)
|
||||
{
|
||||
if(!ocloginit) oc_loginit();
|
||||
oc_logclose();
|
||||
if(file == NULL || strlen(file) == 0) {
|
||||
/* use stderr*/
|
||||
oclogstream = stderr;
|
||||
oclogfile = NULL;
|
||||
ocsystemfile = 1;
|
||||
} else {
|
||||
int fd;
|
||||
oclogfile = (char*)malloc(strlen(file)+1);
|
||||
strcpy(oclogfile,file);
|
||||
oclogstream = NULL;
|
||||
/* We need to deal with this file carefully
|
||||
to avoid unauthorized access*/
|
||||
fd = open(oclogfile,O_WRONLY|O_APPEND|O_CREAT,0600);
|
||||
if(fd >= 0) {
|
||||
oclogstream = fdopen(fd,"a");
|
||||
} else {
|
||||
free(oclogfile);
|
||||
oclogfile = NULL;
|
||||
oc_setlogging(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Close the logging output file (unless it is stderr).
|
||||
Logging is still enabled.
|
||||
*/
|
||||
|
||||
void
|
||||
oc_logclose(void)
|
||||
{
|
||||
if(oclogstream != NULL && !ocsystemfile) {
|
||||
assert(oclogfile != NULL && oclogstream != NULL);
|
||||
fclose(oclogstream);
|
||||
}
|
||||
if(oclogfile != NULL) free(oclogfile);
|
||||
oclogstream = NULL;
|
||||
oclogfile = NULL;
|
||||
ocsystemfile = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Send logging messages. This uses a variable
|
||||
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.
|
||||
*/
|
||||
|
||||
void
|
||||
oc_log(int tag, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char* prefix;
|
||||
if(!oclogging || oclogstream == NULL) return;
|
||||
|
||||
switch (tag) {
|
||||
case LOGWARN: prefix = "Warning:"; break;
|
||||
case LOGERR: prefix = "Error: "; break;
|
||||
case LOGNOTE: prefix = "Note: "; break;
|
||||
case LOGDBG: prefix = "Debug: "; break;
|
||||
default:
|
||||
fprintf(oclogstream,"Error: Bad log prefix: %d\n",tag);
|
||||
prefix = "Error: ";
|
||||
break;
|
||||
}
|
||||
fprintf(oclogstream,"%s:",prefix);
|
||||
|
||||
if(format != NULL) {
|
||||
va_start(args, format);
|
||||
vfprintf(oclogstream, format, args);
|
||||
va_end( args );
|
||||
}
|
||||
fprintf(oclogstream, "\n" );
|
||||
fflush(oclogstream);
|
||||
}
|
||||
|
||||
/*!
|
||||
Send arbitrarily long text as a logging message.
|
||||
Each line will be sent using oc_log 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.
|
||||
*/
|
||||
|
||||
void
|
||||
oc_logtext(int tag, const char* text)
|
||||
{
|
||||
char line[1024];
|
||||
size_t delta = 0;
|
||||
const char* eol = text;
|
||||
|
||||
if(!oclogging || oclogstream == NULL) return;
|
||||
|
||||
while(*text) {
|
||||
eol = strchr(text,'\n');
|
||||
if(eol == NULL)
|
||||
delta = strlen(text);
|
||||
else
|
||||
delta = (eol - text);
|
||||
if(delta > 0) memcpy(line,text,delta);
|
||||
line[delta] = '\0';
|
||||
fprintf(oclogstream," %s\n",line);
|
||||
text = eol+1;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
20
oc2/oclog.h
Normal file
20
oc2/oclog.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCLOG_H
|
||||
#define OCLOG_H
|
||||
|
||||
#define LOGNOTE 0
|
||||
#define LOGWARN 1
|
||||
#define LOGERR 2
|
||||
#define LOGDBG 3
|
||||
|
||||
extern void oc_loginit(void);
|
||||
extern int oc_setlogging(int tf);
|
||||
extern int oc_logopen(const char* file);
|
||||
extern void oc_logclose(void);
|
||||
|
||||
extern void oc_log(int tag, const char* fmt, ...);
|
||||
extern void oc_logtext(int tag, const char* text);
|
||||
|
||||
#endif /*OCLOG_H*/
|
708
oc2/ocnode.c
Normal file
708
oc2/ocnode.c
Normal file
@ -0,0 +1,708 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#include "ocinternal.h"
|
||||
#include "occompile.h"
|
||||
#include "ocdebug.h"
|
||||
|
||||
static const unsigned int MAX_UINT = 0xffffffff;
|
||||
|
||||
static int mergedas1(OCnode* dds, OCnode* das);
|
||||
static int mergedods1(OCnode* dds, OCnode* das);
|
||||
static char* pathtostring(OClist* path, char* separator, int usecdfname);
|
||||
static void computefullname(OCnode* node);
|
||||
|
||||
/* Process ocnodes to fix various semantic issues*/
|
||||
void
|
||||
occomputesemantics(OClist* ocnodes)
|
||||
{
|
||||
unsigned int i,j;
|
||||
OCASSERT((ocnodes != NULL));
|
||||
for(i=0;i<oclistlength(ocnodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(ocnodes,i);
|
||||
/* set the container for dims*/
|
||||
if(node->octype == OC_Dimension && node->dim.array != NULL) {
|
||||
node->container = node->dim.array->container;
|
||||
}
|
||||
}
|
||||
/* Fill in array.sizes */
|
||||
for(i=0;i<oclistlength(ocnodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(ocnodes,i);
|
||||
if(node->array.rank > 0) {
|
||||
node->array.sizes = (size_t*)malloc(node->array.rank*sizeof(size_t));
|
||||
for(j=0;j<node->array.rank;j++) {
|
||||
OCnode* dim = (OCnode*)oclistget(node->array.dimensions,j);
|
||||
node->array.sizes[j] = dim->dim.declsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
occomputefullnames(OCnode* root)
|
||||
{
|
||||
unsigned int i;
|
||||
if(root->name != NULL) computefullname(root);
|
||||
if(root->subnodes != NULL) { /* recurse*/
|
||||
for(i=0;i<oclistlength(root->subnodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(root->subnodes,i);
|
||||
occomputefullnames(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
computefullname(OCnode* node)
|
||||
{
|
||||
char* tmp;
|
||||
char* fullname;
|
||||
OClist* path;
|
||||
|
||||
OCASSERT((node->name != NULL));
|
||||
path = oclistnew();
|
||||
occollectpathtonode(node,path);
|
||||
tmp = pathtostring(path,PATHSEPARATOR,1);
|
||||
if(tmp == NULL) {
|
||||
fullname = nulldup(node->name);
|
||||
} else {
|
||||
fullname = tmp;
|
||||
}
|
||||
node->fullname = fullname;
|
||||
oclistfree(path);
|
||||
}
|
||||
|
||||
/* Convert path to a string; leave off the dataset name*/
|
||||
static char*
|
||||
pathtostring(OClist* path, char* separator, int usecdfname)
|
||||
{
|
||||
int slen,i,len;
|
||||
char* pathname;
|
||||
if(path == NULL || (len = oclistlength(path))==0) return NULL;
|
||||
for(slen=0,i=0;i<len;i++) {
|
||||
OCnode* node = (OCnode*)oclistget(path,i);
|
||||
if(node->container == NULL || node->name == NULL) continue;
|
||||
slen += strlen(node->name);
|
||||
}
|
||||
slen += ((len-1)*strlen(separator));
|
||||
slen += 1; /* for null terminator*/
|
||||
pathname = (char*)ocmalloc(slen);
|
||||
MEMCHECK(pathname,NULL);
|
||||
pathname[0] = '\0';
|
||||
for(i=0;i<len;i++) {
|
||||
OCnode* node = (OCnode*)oclistget(path,i);
|
||||
if(node->container == NULL || node->name == NULL) continue;
|
||||
if(strlen(pathname) > 0) strcat(pathname,separator);
|
||||
strcat(pathname,node->name);
|
||||
}
|
||||
return pathname;
|
||||
}
|
||||
|
||||
/* Collect the set of nodes ending in "node"*/
|
||||
void
|
||||
occollectpathtonode(OCnode* node, OClist* path)
|
||||
{
|
||||
if(node == NULL) return;
|
||||
occollectpathtonode(node->container,path);
|
||||
oclistpush(path,(ocelem)node);
|
||||
}
|
||||
|
||||
OCnode*
|
||||
ocnode_new(char* name, OCtype ptype, OCnode* root)
|
||||
{
|
||||
OCnode* cdf = (OCnode*)ocmalloc(sizeof(OCnode));
|
||||
MEMCHECK(cdf,(OCnode*)NULL);
|
||||
memset((void*)cdf,0,sizeof(OCnode));
|
||||
cdf->header.magic = OCMAGIC;
|
||||
cdf->header.occlass = OC_Node;
|
||||
cdf->name = (name?nulldup(name):NULL);
|
||||
cdf->octype = ptype;
|
||||
cdf->array.dimensions = NULL;
|
||||
cdf->root = root;
|
||||
return cdf;
|
||||
}
|
||||
|
||||
OCattribute*
|
||||
makeattribute(char* name, OCtype ptype, OClist* values)
|
||||
{
|
||||
OCattribute* att = (OCattribute*)ocmalloc(sizeof(OCattribute)); /* ocmalloc zeros*/
|
||||
MEMCHECK(att,(OCattribute*)NULL);
|
||||
att->name = nulldup(name);
|
||||
att->etype = ptype;
|
||||
att->nvalues = oclistlength(values);
|
||||
att->values = NULL;
|
||||
if(att->nvalues > 0) {
|
||||
int i;
|
||||
att->values = (char**)ocmalloc(sizeof(char*)*att->nvalues);
|
||||
for(i=0;i<att->nvalues;i++)
|
||||
att->values[i] = nulldup((char*)oclistget(values,i));
|
||||
}
|
||||
return att;
|
||||
}
|
||||
|
||||
static void
|
||||
marklostattribute(OCnode* att)
|
||||
{
|
||||
oc_log(LOGWARN,"Lost attribute: %s",att->name);
|
||||
}
|
||||
|
||||
void
|
||||
ocroot_free(OCnode* root)
|
||||
{
|
||||
OCtree* tree;
|
||||
OCstate* state;
|
||||
int i;
|
||||
|
||||
if(root == NULL || root->tree == NULL) return;
|
||||
|
||||
tree = root->tree;
|
||||
state = tree->state;
|
||||
|
||||
/* Free up the OCDATA instance, if any */
|
||||
if(tree->data.data != NULL)
|
||||
ocdata_free(state,tree->data.data);
|
||||
|
||||
for(i=0;i<oclistlength(state->trees);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(state->trees,i);
|
||||
if(root == node)
|
||||
oclistremove(state->trees,i);
|
||||
}
|
||||
/* Note: it is ok if state->trees does not contain this root */
|
||||
octree_free(tree);
|
||||
}
|
||||
|
||||
void
|
||||
octree_free(OCtree* tree)
|
||||
{
|
||||
if(tree == NULL) return;
|
||||
ocnodes_free(tree->nodes);
|
||||
ocfree(tree->constraint);
|
||||
ocfree(tree->text);
|
||||
if(tree->data.xdrs != NULL) {
|
||||
xxdr_free(tree->data.xdrs);
|
||||
}
|
||||
ocfree(tree->data.filename); /* may be null */
|
||||
if(tree->data.file != NULL) fclose(tree->data.file);
|
||||
ocfree(tree->data.memory);
|
||||
ocfree(tree);
|
||||
}
|
||||
|
||||
void
|
||||
ocnodes_free(OClist* nodes)
|
||||
{
|
||||
unsigned int i,j;
|
||||
for(i=0;i<oclistlength(nodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(nodes,i);
|
||||
ocfree(node->name);
|
||||
ocfree(node->fullname);
|
||||
while(oclistlength(node->att.values) > 0) {
|
||||
char* value = (char*)oclistpop(node->att.values);
|
||||
ocfree(value);
|
||||
}
|
||||
while(oclistlength(node->attributes) > 0) {
|
||||
OCattribute* attr = (OCattribute*)oclistpop(node->attributes);
|
||||
ocfree(attr->name);
|
||||
/* If the attribute type is string, then we need to free them*/
|
||||
if(attr->etype == OC_String || attr->etype == OC_URL) {
|
||||
char** strings = (char**)attr->values;
|
||||
for(j=0;j<attr->nvalues;j++) {ocfree(*strings); strings++;}
|
||||
}
|
||||
ocfree(attr->values);
|
||||
ocfree(attr);
|
||||
}
|
||||
if(node->array.dimensions != NULL) oclistfree(node->array.dimensions);
|
||||
if(node->subnodes != NULL) oclistfree(node->subnodes);
|
||||
if(node->att.values != NULL) oclistfree(node->att.values);
|
||||
if(node->attributes != NULL) oclistfree(node->attributes);
|
||||
ocfree(node);
|
||||
}
|
||||
oclistfree(nodes);
|
||||
}
|
||||
|
||||
/*
|
||||
In order to be as compatible as possible with libdap,
|
||||
we try to use the same algorithm for DAS->DDS matching.
|
||||
As described there, the algorithm is as follows.
|
||||
If the [attribute] name contains one or
|
||||
more field separators then look for a [DDS]variable whose
|
||||
name matches exactly. If the name contains no field separators then
|
||||
the look first in the top level [of the DDS] and then in all subsequent
|
||||
levels and return the first occurrence found. In general, this
|
||||
searches constructor types in the order in which they appear
|
||||
in the DDS, but there is no requirement that it do so.
|
||||
|
||||
Note: If a dataset contains two constructor types which have field names
|
||||
that are the same (say point.x and pair.x) one should use fully qualified
|
||||
names to get each of those variables.
|
||||
*/
|
||||
|
||||
int
|
||||
ocddsdasmerge(OCstate* state, OCnode* dasroot, OCnode* ddsroot)
|
||||
{
|
||||
OClist* dasglobals = oclistnew();
|
||||
OClist* dodsglobals = oclistnew(); /* top-level DODS_XXX {...} */
|
||||
OClist* dasnodes = oclistnew();
|
||||
OClist* varnodes = oclistnew();
|
||||
OClist* ddsnodes;
|
||||
unsigned int i,j;
|
||||
|
||||
if(dasroot->tree == NULL || dasroot->tree->dxdclass != OCDAS)
|
||||
return OCTHROW(OC_EINVAL);
|
||||
if(ddsroot->tree == NULL || (ddsroot->tree->dxdclass != OCDDS
|
||||
&& ddsroot->tree->dxdclass != OCDATADDS))
|
||||
return OCTHROW(OC_EINVAL);
|
||||
|
||||
ddsnodes = ddsroot->tree->nodes;
|
||||
|
||||
/* 1. collect all the relevant DAS nodes;
|
||||
namely those that contain at least one
|
||||
attribute value.
|
||||
Simultaneously look for potential ambiguities
|
||||
if found; complain but continue: result are indeterminate.
|
||||
also collect globals separately*/
|
||||
for(i=0;i<oclistlength(dasroot->tree->nodes);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dasroot->tree->nodes,i);
|
||||
int hasattributes = 0;
|
||||
if(das->octype == OC_Attribute) continue; /* ignore these for now*/
|
||||
if(das->name == NULL || das->att.isglobal) {
|
||||
oclistpush(dasglobals,(ocelem)das);
|
||||
continue;
|
||||
}
|
||||
if(das->att.isdods) {
|
||||
oclistpush(dodsglobals,(ocelem)das);
|
||||
continue;
|
||||
}
|
||||
for(j=0;j<oclistlength(das->subnodes);j++) {
|
||||
OCnode* subnode = (OCnode*)oclistget(das->subnodes,j);
|
||||
if(subnode->octype == OC_Attribute) {hasattributes = 1; break;}
|
||||
}
|
||||
if(hasattributes) {
|
||||
/* Look for previously collected nodes with same name*/
|
||||
for(j=0;j<oclistlength(dasnodes);j++) {
|
||||
OCnode* das2 = (OCnode*)oclistget(dasnodes,j);
|
||||
if(das->name == NULL || das2->name == NULL) continue;
|
||||
if(strcmp(das->name,das2->name)==0) {
|
||||
oc_log(LOGWARN,"oc_mergedas: potentially ambiguous DAS name: %s",das->name);
|
||||
}
|
||||
}
|
||||
oclistpush(dasnodes,(ocelem)das);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. collect all the leaf DDS nodes (of type OC_Atomic)*/
|
||||
for(i=0;i<oclistlength(ddsnodes);i++) {
|
||||
OCnode* dds = (OCnode*)oclistget(ddsnodes,i);
|
||||
if(dds->octype == OC_Atomic) oclistpush(varnodes,(ocelem)dds);
|
||||
}
|
||||
|
||||
/* 3. For each das node, locate matching DDS node(s) and attach
|
||||
attributes to the DDS node(s).
|
||||
Match means:
|
||||
1. DAS->fullname :: DDS->fullname
|
||||
2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
|
||||
3. DAS->name :: DDS->name
|
||||
*/
|
||||
for(i=0;i<oclistlength(dasnodes);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dasnodes,i);
|
||||
for(j=0;j<oclistlength(varnodes);j++) {
|
||||
OCnode* dds = (OCnode*)oclistget(varnodes,j);
|
||||
if(strcmp(das->fullname,dds->fullname)==0
|
||||
|| strcmp(das->name,dds->fullname)==0
|
||||
|| strcmp(das->name,dds->name)==0) {
|
||||
mergedas1(dds,das);
|
||||
/* remove from dasnodes list*/
|
||||
oclistset(dasnodes,i,(ocelem)NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 4. If there are attributes left, then complain about them being lost.*/
|
||||
for(i=0;i<oclistlength(dasnodes);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dasnodes,i);
|
||||
if(das != NULL) marklostattribute(das);
|
||||
}
|
||||
|
||||
/* 5. Assign globals*/
|
||||
for(i=0;i<oclistlength(dasglobals);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dasglobals,i);
|
||||
mergedas1(ddsroot,das);
|
||||
}
|
||||
/* 6. Assign DODS_*/
|
||||
for(i=0;i<oclistlength(dodsglobals);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dodsglobals,i);
|
||||
mergedods1(ddsroot,das);
|
||||
}
|
||||
/* cleanup*/
|
||||
oclistfree(dasglobals);
|
||||
oclistfree(dodsglobals);
|
||||
oclistfree(dasnodes);
|
||||
oclistfree(varnodes);
|
||||
return OCTHROW(OC_NOERR);
|
||||
}
|
||||
|
||||
static int
|
||||
mergedas1(OCnode* dds, OCnode* das)
|
||||
{
|
||||
unsigned int i;
|
||||
int stat = OC_NOERR;
|
||||
if(das == NULL) return OC_NOERR; /* nothing to do */
|
||||
if(dds->attributes == NULL) dds->attributes = oclistnew();
|
||||
/* assign the simple attributes in the das set to this dds node*/
|
||||
for(i=0;i<oclistlength(das->subnodes);i++) {
|
||||
OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
|
||||
if(attnode->octype == OC_Attribute) {
|
||||
OCattribute* att = makeattribute(attnode->name,
|
||||
attnode->etype,
|
||||
attnode->att.values);
|
||||
oclistpush(dds->attributes,(ocelem)att);
|
||||
}
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
static int
|
||||
mergedods1(OCnode* dds, OCnode* dods)
|
||||
{
|
||||
unsigned int i;
|
||||
int stat = OC_NOERR;
|
||||
if(dods == NULL) return OC_NOERR; /* nothing to do */
|
||||
OCASSERT(dods->octype == OC_Attributeset);
|
||||
if(dds->attributes == NULL) dds->attributes = oclistnew();
|
||||
/* assign the simple attributes in the das set to this dds node
|
||||
with renaming to tag as DODS_
|
||||
*/
|
||||
for(i=0;i<oclistlength(dods->subnodes);i++) {
|
||||
OCnode* attnode = (OCnode*)oclistget(dods->subnodes,i);
|
||||
if(attnode->octype == OC_Attribute) {
|
||||
OCattribute* att;
|
||||
/* prefix the attribute name with the name of the attribute
|
||||
set plus "."
|
||||
*/
|
||||
size_t len = strlen(attnode->name)
|
||||
+ strlen(dods->name)
|
||||
+ strlen(".")
|
||||
+ 1; /*null*/
|
||||
char* newname = (char*)malloc(len);
|
||||
if(newname == NULL) return OC_ENOMEM;
|
||||
strcpy(newname,dods->name);
|
||||
strcat(newname,".");
|
||||
strcat(newname,attnode->name);
|
||||
att = makeattribute(newname,
|
||||
attnode->etype,
|
||||
attnode->att.values);
|
||||
free(newname);
|
||||
oclistpush(dds->attributes,(ocelem)att);
|
||||
}
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
int
|
||||
ocddsdasmerge(OCstate* state, OCnode* ddsroot, OCnode* dasroot)
|
||||
{
|
||||
int i,j;
|
||||
int stat = OC_NOERR;
|
||||
OClist* globals = oclistnew();
|
||||
if(dasroot == NULL) return OCTHROW(stat);
|
||||
/* Start by looking for global attributes*/
|
||||
for(i=0;i<oclistlength(dasroot->subnodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(dasroot->subnodes,i);
|
||||
if(node->att.isglobal) {
|
||||
for(j=0;j<oclistlength(node->subnodes);j++) {
|
||||
OCnode* attnode = (OCnode*)oclistget(node->subnodes,j);
|
||||
Attribute* att = makeattribute(attnode->name,
|
||||
attnode->etype,
|
||||
attnode->att.values);
|
||||
oclistpush(globals,(ocelem)att);
|
||||
}
|
||||
}
|
||||
}
|
||||
ddsroot->attributes = globals;
|
||||
/* Now try to match subnode names with attribute set names*/
|
||||
for(i=0;i<oclistlength(dasroot->subnodes);i++) {
|
||||
OCnode* das = (OCnode*)oclistget(dasroot->subnodes,i);
|
||||
int match = 0;
|
||||
if(das->att.isglobal) continue;
|
||||
if(das->octype == OC_Attributeset) {
|
||||
for(j=0;j<oclistlength(ddsroot->subnodes) && !match;j++) {
|
||||
OCnode* dds = (OCnode*)oclistget(ddsroot->subnodes,j);
|
||||
if(strcmp(das->name,dds->name) == 0) {
|
||||
match = 1;
|
||||
stat = mergedas1(dds,das);
|
||||
if(stat != OC_NOERR) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!match) {marklostattribute(das);}
|
||||
}
|
||||
if(stat == OC_NOERR) ddsroot->attributed = 1;
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
|
||||
/* Merge das attributes into the dds node*/
|
||||
|
||||
static int
|
||||
mergedas1(OCnode* dds, OCnode* das)
|
||||
{
|
||||
int i,j;
|
||||
int stat = OC_NOERR;
|
||||
if(dds->attributes == NULL) dds->attributes = oclistnew();
|
||||
/* assign the simple attributes in the das set to this dds node*/
|
||||
for(i=0;i<oclistlength(das->subnodes);i++) {
|
||||
OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
|
||||
if(attnode->octype == OC_Attribute) {
|
||||
Attribute* att = makeattribute(attnode->name,
|
||||
attnode->etype,
|
||||
attnode->att.values);
|
||||
oclistpush(dds->attributes,(ocelem)att);
|
||||
}
|
||||
}
|
||||
/* Try to merge any enclosed sets with subnodes of dds*/
|
||||
for(i=0;i<oclistlength(das->subnodes);i++) {
|
||||
OCnode* dasnode = (OCnode*)oclistget(das->subnodes,i);
|
||||
int match = 0;
|
||||
if(dasnode->octype == OC_Attribute) continue; /* already dealt with above*/
|
||||
for(j=0;j<oclistlength(dds->subnodes) && !match;j++) {
|
||||
OCnode* ddsnode = (OCnode*)oclistget(dds->subnodes,j);
|
||||
if(strcmp(dasnode->name,ddsnode->name) == 0) {
|
||||
match = 1;
|
||||
stat = mergedas1(ddsnode,dasnode);
|
||||
if(stat != OC_NOERR) break;
|
||||
}
|
||||
}
|
||||
if(!match) {marklostattribute(dasnode);}
|
||||
}
|
||||
return OCTHROW(stat);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ocuncorrelate(OCnode* root)
|
||||
{
|
||||
OCtree* tree = root->tree;
|
||||
unsigned int i;
|
||||
if(tree == NULL) return;
|
||||
for(i=0;i<oclistlength(tree->nodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(tree->nodes,i);
|
||||
node->datadds = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static OCerror
|
||||
occorrelater(OCnode* dds, OCnode* dxd)
|
||||
{
|
||||
int i,j;
|
||||
OCerror ocstat = OC_NOERR;
|
||||
|
||||
if(dds->octype != dxd->octype) {
|
||||
OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
|
||||
}
|
||||
if(dxd->name != NULL && dxd->name != NULL
|
||||
&& strcmp(dxd->name,dds->name) != 0) {
|
||||
OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
|
||||
} else if(dxd->name != dxd->name) { /* test NULL==NULL */
|
||||
OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
|
||||
}
|
||||
|
||||
if(dxd->array.rank != dds->array.rank) {
|
||||
OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
|
||||
}
|
||||
|
||||
dds->datadds = dxd;
|
||||
|
||||
switch (dds->octype) {
|
||||
case OC_Dataset:
|
||||
case OC_Structure:
|
||||
case OC_Grid:
|
||||
case OC_Sequence:
|
||||
/* Remember: there may be fewer datadds fields than dds fields */
|
||||
for(i=0;i<oclistlength(dxd->subnodes);i++) {
|
||||
OCnode* dxd1 = (OCnode*)oclistget(dxd->subnodes,i);
|
||||
for(j=0;j<oclistlength(dds->subnodes);j++) {
|
||||
OCnode* dds1 = (OCnode*)oclistget(dds->subnodes,j);
|
||||
if(strcmp(dxd1->name,dds1->name) == 0) {
|
||||
ocstat = occorrelater(dds1,dxd1);
|
||||
if(ocstat != OC_NOERR) {OCTHROWCHK(ocstat); goto fail;}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OC_Dimension:
|
||||
case OC_Atomic:
|
||||
break;
|
||||
default: OCPANIC1("unexpected node type: %d",dds->octype);
|
||||
}
|
||||
/* Correlate the dimensions */
|
||||
if(dds->array.rank > 0) {
|
||||
for(i=0;i<oclistlength(dxd->subnodes);i++) {
|
||||
OCnode* ddsdim = (OCnode*)oclistget(dds->array.dimensions,i);
|
||||
OCnode* dxddim = (OCnode*)oclistget(dxd->array.dimensions,i);
|
||||
ocstat = occorrelater(ddsdim,dxddim);
|
||||
if(!ocstat) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
return OCTHROW(ocstat);
|
||||
|
||||
}
|
||||
|
||||
OCerror
|
||||
occorrelate(OCnode* dds, OCnode* dxd)
|
||||
{
|
||||
if(dds == NULL || dxd == NULL) return OCTHROW(OC_EINVAL);
|
||||
ocuncorrelate(dds);
|
||||
return occorrelater(dds,dxd);
|
||||
}
|
||||
|
||||
/*
|
||||
Mark cacheable those atomic String/URL typed nodes
|
||||
that are contained only in structures with rank > 0.
|
||||
*/
|
||||
void
|
||||
ocmarkcacheable(OCstate* state, OCnode* ddsroot)
|
||||
{
|
||||
int i,j;
|
||||
#if 0
|
||||
int ok;
|
||||
#endif
|
||||
OClist* treenodes = ddsroot->tree->nodes;
|
||||
OClist* path = oclistnew();
|
||||
for(i=0;i<oclistlength(treenodes);i++) {
|
||||
OCnode* node = (OCnode*)oclistget(treenodes,i);
|
||||
if(node->octype != OC_Atomic) continue;
|
||||
if(node->etype != OC_String && node->etype != OC_URL) continue;
|
||||
/* collect node path */
|
||||
oclistclear(path);
|
||||
occollectpathtonode(node,path);
|
||||
#if 0
|
||||
ok = 1;
|
||||
#endif
|
||||
for(j=1;j<oclistlength(path)-1;j++) {/* skip top level dataset and node itself*/
|
||||
OCnode* pathnode = (OCnode*)oclistget(path,j);
|
||||
if(pathnode->octype != OC_Structure
|
||||
|| pathnode->array.rank > 0) {
|
||||
#if 0
|
||||
ok=0;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if(ok) {
|
||||
node->cache.cacheable = 1;
|
||||
node->cache.valid = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
oclistfree(path);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void*
|
||||
oclinearize(OCtype etype, unsigned int nstrings, char** strings)
|
||||
{
|
||||
int i;
|
||||
size_t typesize;
|
||||
char* memp;
|
||||
char* memory;
|
||||
|
||||
if(nstrings == 0) return NULL;
|
||||
typesize = octypesize(etype);
|
||||
memory = (char*)ocmalloc(nstrings*typesize);
|
||||
MEMCHECK(memory,NULL);
|
||||
memp = memory;
|
||||
for(i=0;i<nstrings;i++) {
|
||||
char* value = strings[i];
|
||||
converttype(etype,value,memp);
|
||||
memp += typesize;
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
static int
|
||||
converttype(OCtype etype, char* value, char* memory)
|
||||
{
|
||||
long iv;
|
||||
unsigned long uiv;
|
||||
double dv;
|
||||
char c[1];
|
||||
int outofrange = 0;
|
||||
#ifdef HAVE_LONG_LONG_INT
|
||||
long long llv;
|
||||
unsigned long long ullv;
|
||||
#endif
|
||||
|
||||
switch (etype) {
|
||||
case OC_Char:
|
||||
if(sscanf(value,"%c",c) != 1) goto fail;
|
||||
*((char*)memory) = c[0];
|
||||
break;
|
||||
case OC_Byte:
|
||||
if(sscanf(value,"%ld",&iv) != 1) goto fail;
|
||||
else if(iv > OC_BYTE_MAX || iv < OC_BYTE_MIN) {iv = OC_BYTE_MAX; outofrange = 1;}
|
||||
*((signed char*)memory) = (signed char)iv;
|
||||
break;
|
||||
case OC_UByte:
|
||||
if(sscanf(value,"%lu",&uiv) != 1) goto fail;
|
||||
else if(uiv > OC_UBYTE_MAX) {uiv = OC_UBYTE_MAX; outofrange = 1;}
|
||||
*((unsigned char*)memory) = (unsigned char)uiv;
|
||||
break;
|
||||
case OC_Int16:
|
||||
if(sscanf(value,"%ld",&iv) != 1) goto fail;
|
||||
else if(iv > OC_INT16_MAX || iv < OC_INT16_MIN) {iv = OC_INT16_MAX; outofrange = 1;}
|
||||
*((signed short*)memory) = (signed short)iv;
|
||||
break;
|
||||
case OC_UInt16:
|
||||
if(sscanf(value,"%lu",&uiv) != 1) goto fail;
|
||||
else if(uiv > OC_UINT16_MAX) {uiv = OC_UINT16_MAX; outofrange = 1;}
|
||||
*((unsigned short*)memory) = (unsigned short)uiv;
|
||||
break;
|
||||
case OC_Int32:
|
||||
if(sscanf(value,"%ld",&iv) != 1) goto fail;
|
||||
else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) {iv = OC_INT32_MAX; outofrange = 1;}
|
||||
*((signed int*)memory) = (signed int)iv;
|
||||
break;
|
||||
case OC_UInt32:
|
||||
if(sscanf(value,"%lu",&uiv) != 1) goto fail;
|
||||
else if(uiv > OC_UINT32_MAX) {uiv = OC_UINT32_MAX; outofrange = 1;}
|
||||
*((unsigned char*)memory) = (unsigned int)uiv;
|
||||
break;
|
||||
#ifdef HAVE_LONG_LONG_INT
|
||||
case OC_Int64:
|
||||
if(sscanf(value,"%lld",&llv) != 1) goto fail;
|
||||
/*else if(iv > OC_INT64_MAX || iv < OC_INT64_MIN) goto fail;*/
|
||||
*((signed long long*)memory) = (signed long long)llv;
|
||||
break;
|
||||
case OC_UInt64:
|
||||
if(sscanf(value,"%llu",&ullv) != 1) goto fail;
|
||||
*((unsigned long long*)memory) = (unsigned long long)ullv;
|
||||
break;
|
||||
#endif
|
||||
case OC_Float32:
|
||||
if(sscanf(value,"%lf",&dv) != 1) goto fail;
|
||||
*((float*)memory) = (float)dv;
|
||||
break;
|
||||
case OC_Float64:
|
||||
if(sscanf(value,"%lf",&dv) != 1) goto fail;
|
||||
*((double*)memory) = (double)dv;
|
||||
break;
|
||||
case OC_String: case OC_URL:
|
||||
*((char**)memory) = nulldup(value);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
if(outofrange)
|
||||
oc_log(LOGWARN,"converttype range failure: %d: %s",etype,value);
|
||||
return 1;
|
||||
fail:
|
||||
oc_log(LOGERR,"converttype bad value: %d: %s",etype,value);
|
||||
return 0;
|
||||
}
|
||||
#endif /*0*/
|
86
oc2/ocnode.h
Normal file
86
oc2/ocnode.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#ifndef OCNODE_H
|
||||
#define OCNODE_H
|
||||
|
||||
/*! Specifies the Diminfo. */
|
||||
/* Track info purely about declared dimensions.
|
||||
More information is included in the Dimdata structure (dim.h)
|
||||
*/
|
||||
typedef struct OCdiminfo {
|
||||
struct OCnode* array; /* defining array node (if known)*/
|
||||
size_t arrayindex; /* rank position ofthis dimension in the array*/
|
||||
size_t declsize; /* from DDS*/
|
||||
} OCdiminfo;
|
||||
|
||||
/*! Specifies the Arrayinfo.*/
|
||||
typedef struct OCarrayinfo {
|
||||
/* The complete set of dimension info applicable to this node*/
|
||||
OClist* dimensions;
|
||||
/* convenience (because they are computed so often*/
|
||||
size_t rank; /* == |dimensions|*/
|
||||
size_t* sizes;
|
||||
} OCarrayinfo;
|
||||
|
||||
/*! Specifies Attribute info */
|
||||
typedef struct OCattribute {
|
||||
char* name;
|
||||
OCtype etype; /* type of the attribute */
|
||||
size_t nvalues;
|
||||
char** values; /* |values| = nvalues*sizeof(char**)*/
|
||||
} OCattribute;
|
||||
|
||||
/*! Specifies the Attinfo.*/
|
||||
/* This is the form as it comes out of the DAS parser*/
|
||||
typedef struct OCattinfo {
|
||||
int isglobal; /* is this supposed to be a global attribute set?*/
|
||||
int isdods; /* is this a global DODS_XXX attribute set */
|
||||
OClist* values; /* oclist<char*>*/
|
||||
} OCattinfo;
|
||||
|
||||
/*! Specifies the OCnode. */
|
||||
struct OCnode {
|
||||
OCheader header; /* class=OC_Node */
|
||||
OCtype octype;
|
||||
OCtype etype; /* essentially the dap type from the dds*/
|
||||
char* name;
|
||||
char* fullname;
|
||||
struct OCnode* container; /* this node is subnode of container */
|
||||
struct OCnode* root; /* root node of tree containing this node */
|
||||
struct OCtree* tree; /* !NULL iff this is a root node */
|
||||
struct OCnode* datadds; /* correlated datadds node, if any */
|
||||
OCdiminfo dim; /* octype == OC_Dimension*/
|
||||
OCarrayinfo array; /* octype == {OC_Structure, OC_Primitive}*/
|
||||
OCattinfo att; /* octype == OC_Attribute */
|
||||
/* primary edge info*/
|
||||
OClist* subnodes; /*oclist<OCnode*>*/
|
||||
/*int attributed;*/ /* 1 if merge was done*/
|
||||
OClist* attributes; /* oclist<OCattribute*>*/
|
||||
};
|
||||
|
||||
#if SIZEOF_SIZE_T == 4
|
||||
#define OCINDETERMINATE ((size_t)0xffffffff)
|
||||
#endif
|
||||
#if SIZEOF_SIZE_T == 8
|
||||
#define OCINDETERMINATE ((size_t)0xffffffffffffffff)
|
||||
#endif
|
||||
|
||||
extern OCnode* ocnode_new(char* name, OCtype ptype, OCnode* root);
|
||||
extern void occollectpathtonode(OCnode* node, OClist* path);
|
||||
extern void occomputefullnames(OCnode* root);
|
||||
extern void occomputesemantics(OClist*);
|
||||
extern void ocaddattribute(OCattribute* attr, OCnode* parent);
|
||||
extern OCattribute* ocmakeattribute(char* name, OCtype ptype, OClist* values);
|
||||
extern size_t ocsetsize(OCnode* node);
|
||||
extern OCerror occorrelate(OCnode*,OCnode*);
|
||||
extern void ocmarkcacheable(OCstate* state, OCnode* ddsroot);
|
||||
|
||||
extern void octree_free(struct OCtree* tree);
|
||||
extern void ocroot_free(OCnode* root);
|
||||
extern void ocnodes_free(OClist*);
|
||||
|
||||
/* Merge DAS with DDS or DATADDS*/
|
||||
extern int ocddsdasmerge(struct OCstate*, OCnode* das, OCnode* dds);
|
||||
|
||||
#endif /*OCNODE_H*/
|
553
oc2/ocrc.c
Normal file
553
oc2/ocrc.c
Normal file
@ -0,0 +1,553 @@
|
||||
/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
|
||||
See the COPYRIGHT file for more information. */
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ocinternal.h"
|
||||
#include "ocdebug.h"
|
||||
#include "oclog.h"
|
||||
|
||||
#include "ocrc.h"
|
||||
|
||||
#define RTAG ']'
|
||||
#define LTAG '['
|
||||
|
||||
#define TRIMCHARS " \t\r\n"
|
||||
|
||||
#define TRIM(x) rctrimright(rctrimleft((x),TRIMCHARS),TRIMCHARS)
|
||||
|
||||
#define HTTPPREFIXDEPRECATED "CURL."
|
||||
#define HTTPPREFIX "HTTP."
|
||||
|
||||
static int parseproxy(OCstate* state, char* v);
|
||||
static int rcreadline(FILE* f, char* more, int morelen);
|
||||
static char* rctrimright(char* more, char* trimchars);
|
||||
static char* rctrimleft(char* more, char* trimchars);
|
||||
|
||||
static void ocdodsrcdump(char* msg, struct OCTriple*, int ntriples);
|
||||
|
||||
static char* curllookup(char* suffix,char* url);
|
||||
|
||||
/* The Username and password are in the URL if the URL is of the form:
|
||||
* http://<name>:<passwd>@<host>/....
|
||||
*/
|
||||
int
|
||||
occredentials_in_url(const char *url)
|
||||
{
|
||||
char *pos = strstr(url, "http://");
|
||||
if (!pos)
|
||||
return 0;
|
||||
pos += 7;
|
||||
if (strchr(pos, '@') && strchr(pos, ':'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ocextract_credentials(const char *url, char **name, char **pw, char **result_url)
|
||||
{
|
||||
char *pos;
|
||||
char *end;
|
||||
char *middle;
|
||||
int up_len = 0;
|
||||
int mid_len = 0;
|
||||
int midpas_len = 0;
|
||||
int url_len = 0;
|
||||
|
||||
if (strchr(url, '@')) {
|
||||
pos = strstr(url, "http://");
|
||||
if (pos)
|
||||
pos += 7;
|
||||
middle = strchr(pos, ':');
|
||||
mid_len = middle - pos;
|
||||
*name = malloc(sizeof(char) * (mid_len + 1));
|
||||
strncpy(*name, pos, mid_len);
|
||||
(*name)[mid_len] = '\0';
|
||||
|
||||
if (middle)
|
||||
middle += 1;
|
||||
|
||||
end = strchr(middle, '@');
|
||||
midpas_len = end - middle;
|
||||
*pw = malloc(sizeof(char) * (midpas_len + 1));
|
||||
strncpy(*pw, middle, midpas_len);
|
||||
(*pw)[midpas_len] = '\0';
|
||||
|
||||
up_len = end - pos;
|
||||
url_len = strlen(url) - up_len;
|
||||
|
||||
*result_url = malloc(sizeof(char) * (url_len + 1));
|
||||
if (!result_url)
|
||||
return OC_ENOMEM;
|
||||
|
||||
strncpy(*result_url, url, pos - url);
|
||||
strncpy(*result_url + (pos - url), end + 1, url_len - (pos - url));
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "URL without username and password: %s:%d\n", sURL, url_len );
|
||||
fprintf(stderr, "URL username and password: %s:%d\n", sUP, up_len);
|
||||
fprintf(stderr, "URL username: %s:%d\n", sUser, mid_len);
|
||||
fprintf(stderr, "URL password: %s:%d\n", sPassword, midpas_len);
|
||||
#endif
|
||||
(*result_url)[url_len] = '\0';
|
||||
|
||||
return OC_NOERR;
|
||||
}
|
||||
else {
|
||||
return OC_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rcreadline(FILE* f, char* more, int morelen)
|
||||
{
|
||||
int i = 0;
|
||||
int c = getc(f);
|
||||
if(c < 0) return 0;
|
||||
for(;;) {
|
||||
if(i < morelen) /* ignore excess characters */
|
||||
more[i++]=c;
|
||||
c = getc(f);
|
||||
if(c < 0) break; /* eof */
|
||||
if(c == '\n') break; /* eol */
|
||||
}
|
||||
/* null terminate more */
|
||||
more[i] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Trim specified characters from front/left */
|
||||
static char*
|
||||
rctrimleft(char* more, char* trimchars)
|
||||
{
|
||||
char* p = more;
|
||||
int c;
|
||||
while((c=*p) != '\0') {if(strchr(trimchars,c) != NULL) p++; else break;}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Trim specified characters from end/right */
|
||||
static char*
|
||||
rctrimright(char* more, char* trimchars)
|
||||
{
|
||||
int len = strlen(more);
|
||||
char* p = more + (len - 1);
|
||||
while(p != more) {if(strchr(trimchars,*p) != NULL) p--; else break;}
|
||||
/* null terminate */
|
||||
p[1] = '\0';
|
||||
return more;
|
||||
}
|
||||
|
||||
static int
|
||||
parseproxy(OCstate* state, char* v)
|
||||
{
|
||||
char *host_pos = NULL;
|
||||
char *port_pos = NULL;
|
||||
|
||||
if(strlen(v) == 0) return OC_NOERR; /* nothing there*/
|
||||
if (occredentials_in_url(v)) {
|
||||
char *result_url = NULL;
|
||||
ocextract_credentials(v, &state->creds.username,
|
||||
&state->creds.password,
|
||||
&result_url);
|
||||
v = result_url;
|
||||
}
|
||||
/* allocating a bit more than likely needed ... */
|
||||
host_pos = strstr(v, "http://");
|
||||
if (host_pos)
|
||||
host_pos += strlen("http://");
|
||||
else
|
||||
host_pos = v;
|
||||
port_pos = strchr(host_pos, ':');
|
||||
if (port_pos) {
|
||||
int host_len;
|
||||
char *port_sep = port_pos;
|
||||
port_pos++;
|
||||
*port_sep = '\0';
|
||||
host_len = strlen(host_pos);
|
||||
state->proxy.host = malloc(sizeof(char) * host_len + 1);
|
||||
if (!state->proxy.host)
|
||||
return OC_ENOMEM;
|
||||
|
||||
strncpy(state->proxy.host, host_pos, host_len);
|
||||
state->proxy.host[host_len] = '\0';
|
||||
|
||||
state->proxy.port = atoi(port_pos);
|
||||
} else {
|
||||
int host_len = strlen(host_pos);
|
||||
state->proxy.host = malloc(sizeof(char) * host_len + 1);
|
||||
if (!state->proxy.host)
|
||||
return OC_ENOMEM;
|
||||
|
||||
strncpy(state->proxy.host, host_pos, host_len);
|
||||
state->proxy.host[host_len] = '\0';
|
||||
|
||||
state->proxy.port = 80;
|
||||
}
|
||||
#if 0
|
||||
state->proxy.host[v_len] = '\0';
|
||||
state->proxy.port = atoi(v);
|
||||
s_len = strlen(v);
|
||||
state->proxy.user = malloc(sizeof(char) * s_len + 1);
|
||||
if (!state->proxy.user)
|
||||
return OC_ENOMEM;
|
||||
strncpy(state->proxy.user, v, s_len);
|
||||
state->proxy.user[s_len] = '\0';
|
||||
p_len = strlen(v);
|
||||
state->proxy.password = malloc(sizeof(char) * p_len + 1);
|
||||
if (!state->proxy.password)
|
||||
return OC_ENOMEM;
|
||||
strncpy(state->proxy.password, v, p_len);
|
||||
state->proxy.password[p_len] = '\0';
|
||||
#endif /*0*/
|
||||
if (ocdebug > 1) {
|
||||
oc_log(LOGNOTE,"host name: %s", state->proxy.host);
|
||||
oc_log(LOGNOTE,"user name: %s", state->creds.username);
|
||||
#ifdef INSECURE
|
||||
oc_log(LOGNOTE,"password: %s", state->creds.password);
|
||||
#endif
|
||||
oc_log(LOGNOTE,"port number: %d", state->proxy.port);
|
||||
}
|
||||
if(v) free(v);
|
||||
return OC_NOERR;
|
||||
}
|
||||
|
||||
/* insertion sort the triplestore based on url */
|
||||
static void
|
||||
sorttriplestore(void)
|
||||
{
|
||||
int i, nsorted;
|
||||
struct OCTriple* sorted = NULL;
|
||||
struct OCTriplestore* ocdodsrc = ocglobalstate.ocdodsrc;
|
||||
|
||||
if(ocdodsrc == NULL) return; /* nothing to sort */
|
||||
if(ocdodsrc->ntriples <= 1) return; /* nothing to sort */
|
||||
if(ocdebug > 2)
|
||||
ocdodsrcdump("initial:",ocdodsrc->triples,ocdodsrc->ntriples);
|
||||
|
||||
sorted = (struct OCTriple*)malloc(sizeof(struct OCTriple)*ocdodsrc->ntriples);
|
||||
if(sorted == NULL) {
|
||||
oc_log(LOGERR,"sorttriplestore: out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
nsorted = 0;
|
||||
while(nsorted < ocdodsrc->ntriples) {
|
||||
int largest;
|
||||
/* locate first non killed entry */
|
||||
for(largest=0;largest<ocdodsrc->ntriples;largest++) {
|
||||
if(ocdodsrc->triples[largest].key[0] != '\0') break;
|
||||
}
|
||||
OCASSERT(ocdodsrc->triples[largest].key[0] != '\0');
|
||||
for(i=0;i<ocdodsrc->ntriples;i++) {
|
||||
if(ocdodsrc->triples[i].key[0] != '\0') { /* avoid empty slots */
|
||||
int lexorder = strcmp(ocdodsrc->triples[i].url,ocdodsrc->triples[largest].url);
|
||||
int leni = strlen(ocdodsrc->triples[i].url);
|
||||
int lenlarge = strlen(ocdodsrc->triples[largest].url);
|
||||
/* this defines the ordering */
|
||||
if(leni == 0 && lenlarge == 0) continue; /* if no urls, then leave in order */
|
||||
if(leni != 0 && lenlarge == 0) largest = i;
|
||||
else if(lexorder > 0) largest = i;
|
||||
}
|
||||
}
|
||||
/* Move the largest entry */
|
||||
OCASSERT(ocdodsrc->triples[largest].key[0] != 0);
|
||||
sorted[nsorted] = ocdodsrc->triples[largest];
|
||||
ocdodsrc->triples[largest].key[0] = '\0'; /* kill entry */
|
||||
nsorted++;
|
||||
if(ocdebug > 2)
|
||||
ocdodsrcdump("pass:",sorted,nsorted);
|
||||
}
|
||||
|
||||
memcpy((void*)ocdodsrc->triples,(void*)sorted,sizeof(struct OCTriple)*nsorted);
|
||||
free(sorted);
|
||||
|
||||
if(ocdebug > 0)
|
||||
ocdodsrcdump("final .dodsrc order:",ocdodsrc->triples,ocdodsrc->ntriples);
|
||||
}
|
||||
|
||||
/* Create a triple store from a file */
|
||||
int
|
||||
ocdodsrc_read(char* basename, char* path)
|
||||
{
|
||||
char line0[MAXRCLINESIZE];
|
||||
FILE *in_file = NULL;
|
||||
int linecount = 0;
|
||||
struct OCTriplestore* ocdodsrc = ocglobalstate.ocdodsrc;
|
||||
|
||||
if(ocdodsrc == NULL) {
|
||||
ocdodsrc = (struct OCTriplestore*)malloc(sizeof(struct OCTriplestore));
|
||||
if(ocdodsrc == NULL) {
|
||||
oc_log(LOGERR,"ocdodsrc_read: out of memory");
|
||||
return 0;
|
||||
}
|
||||
ocglobalstate.ocdodsrc = ocdodsrc;
|
||||
}
|
||||
ocdodsrc->ntriples = 0;
|
||||
|
||||
in_file = fopen(path, "r"); /* Open the file to read it */
|
||||
if (in_file == NULL) {
|
||||
oc_log(LOGERR, "Could not open configuration file: %s",basename);
|
||||
return OC_EPERM;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
char *line,*key,*value;
|
||||
if(!rcreadline(in_file,line0,sizeof(line0))) break;
|
||||
linecount++;
|
||||
if(linecount >= MAXRCLINES) {
|
||||
oc_log(LOGERR, ".dodsrc has too many lines");
|
||||
return 0;
|
||||
}
|
||||
line = line0;
|
||||
/* check for comment */
|
||||
if (line[0] == '#') continue;
|
||||
/* trim leading blanks */
|
||||
line = rctrimleft(line,TRIMCHARS);
|
||||
if(strlen(line) >= MAXRCLINESIZE) {
|
||||
oc_log(LOGERR, "%s line too long: %s",basename,line0);
|
||||
return 0;
|
||||
}
|
||||
/* parse the line */
|
||||
ocdodsrc->triples[ocdodsrc->ntriples].url[0] = '\0'; /*assume no url*/
|
||||
if(line[0] == LTAG) {
|
||||
char* url = ++line;
|
||||
char* rtag = strchr(line,RTAG);
|
||||
if(rtag == NULL) {
|
||||
oc_log(LOGERR, "Malformed [url] in %s entry: %s",basename,line);
|
||||
continue;
|
||||
}
|
||||
line = rtag + 1;
|
||||
*rtag = '\0';
|
||||
/* trim again */
|
||||
line = rctrimleft(line,TRIMCHARS);
|
||||
/* save the url */
|
||||
strcpy(ocdodsrc->triples[ocdodsrc->ntriples].url,TRIM(url));
|
||||
}
|
||||
if(strlen(line)==0) continue; /* empty line */
|
||||
/* split off key and value */
|
||||
key=line;
|
||||
value = strchr(line, '=');
|
||||
if(value == NULL) {
|
||||
/* add fake '=1' */
|
||||
if(strlen(line) + strlen("=1") >= MAXRCLINESIZE) {
|
||||
oc_log(LOGERR, "%s entry too long: %s",basename,line);
|
||||
continue;
|
||||
}
|
||||
strcat(line,"=1");
|
||||
value = strchr(line,'=');
|
||||
}
|
||||
*value = '\0';
|
||||
value++;
|
||||
strcpy(ocdodsrc->triples[ocdodsrc->ntriples].key,TRIM(key));
|
||||
strcpy(ocdodsrc->triples[ocdodsrc->ntriples].value,TRIM(value));
|
||||
ocdodsrc->ntriples++;
|
||||
}
|
||||
fclose(in_file);
|
||||
sorttriplestore();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ocdodsrc_process(OCstate* state)
|
||||
{
|
||||
int stat = 0;
|
||||
char* value;
|
||||
char* url = ocuribuild(state->uri,NULL,NULL,OCURIENCODE);
|
||||
struct OCTriplestore* ocdodsrc = ocglobalstate.ocdodsrc;
|
||||
|
||||
if(ocdodsrc == NULL) goto done;
|
||||
value = curllookup("DEFLATE",url);
|
||||
if(value != NULL) {
|
||||
if(atoi(value)) state->curlflags.compress = 1;
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"Compression: %ld", state->curlflags.compress);
|
||||
}
|
||||
if((value = curllookup("VERBOSE",url)) != NULL) {
|
||||
if(atoi(value)) state->curlflags.verbose = 1;
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"curl.verbose: %ld", state->curlflags.verbose);
|
||||
}
|
||||
if((value = curllookup("TIMEOUT",url)) != NULL) {
|
||||
if(atoi(value)) state->curlflags.timeout = atoi(value);
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"curl.timeout: %ld", state->curlflags.timeout);
|
||||
}
|
||||
|
||||
if((value = curllookup("COOKIEFILE",url)) != NULL) {
|
||||
state->curlflags.cookiefile = strdup(TRIM(value));
|
||||
if(!state->curlflags.cookiefile) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"COOKIEFILE: %s", state->curlflags.cookiefile);
|
||||
}
|
||||
if((value = curllookup("COOKIEJAR",url))
|
||||
|| (value = curllookup("COOKIE_JAR",url))) {
|
||||
state->curlflags.cookiejar = strdup(TRIM(value));
|
||||
if(!state->curlflags.cookiejar) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"COOKIEJAR: %s", state->curlflags.cookiejar);
|
||||
}
|
||||
|
||||
/* Some servers (e.g. thredds) appear to require a place
|
||||
to put cookies in order for some security functions to work
|
||||
*/
|
||||
if(state->curlflags.cookiejar == NULL
|
||||
&& state->curlflags.cookiefile == NULL) {
|
||||
state->curlflags.cookiefile = strdup("");
|
||||
}
|
||||
|
||||
if((value = curllookup("PROXY_SERVER",url)) != NULL) {
|
||||
stat = parseproxy(state,TRIM(value));
|
||||
if(stat != OC_NOERR) goto done;
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.VALIDATE",url)) != NULL) {
|
||||
if(atoi(value)) state->ssl.validate = 1;
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"CURL.SSL.VALIDATE: %ld", state->ssl.validate);
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.CERTIFICATE",url)) != NULL) {
|
||||
state->ssl.certificate = strdup(TRIM(value));
|
||||
if(!state->ssl.certificate) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"CREDENTIALS.SSL.CERTIFICATE: %s", state->ssl.certificate);
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.KEY",url)) != NULL) {
|
||||
state->ssl.key = strdup(TRIM(value));
|
||||
if(!state->ssl.key) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"CREDENTIALS.SSL.KEY: %s", state->ssl.key);
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.KEYPASSWORD",url)) != NULL) {
|
||||
state->ssl.keypasswd = strdup(TRIM(value));
|
||||
if(!state->ssl.keypasswd) {stat = OC_ENOMEM; goto done;}
|
||||
#ifdef INSECURE
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"CREDENTIALS.SSL.KEYPASSWORD: %s", state->ssl.keypasswd);
|
||||
#endif
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.CAINFO",url)) != NULL) {
|
||||
state->ssl.cainfo = strdup(TRIM(value));
|
||||
if(!state->ssl.cainfo) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"SSL.CAINFO: %s", state->ssl.cainfo);
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.CAPATH",url)) != NULL) {
|
||||
state->ssl.capath = strdup(TRIM(value));
|
||||
if(!state->ssl.capath) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"SSL.CAPATH: %s", state->ssl.capath);
|
||||
}
|
||||
|
||||
if((value = curllookup("SSL.VERIFYPEER",url)) != NULL) {
|
||||
char* s = strdup(TRIM(value));
|
||||
int tf = 0;
|
||||
if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
|
||||
tf = 0;
|
||||
else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
|
||||
tf = 1;
|
||||
else
|
||||
tf = 1; /* default if not null */
|
||||
state->ssl.verifypeer = tf;
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"SSL.VERIFYPEER: %d", state->ssl.verifypeer);
|
||||
}
|
||||
|
||||
if((value = curllookup("CREDENTIALS.USER",url)) != NULL) {
|
||||
state->creds.username = strdup(TRIM(value));
|
||||
if(!state->creds.username) {stat = OC_ENOMEM; goto done;}
|
||||
if(ocdebug > 0)
|
||||
oc_log(LOGNOTE,"CREDENTIALS.USER: %s", state->creds.username);
|
||||
}
|
||||
|
||||
if((value = curllookup("CREDENTIALS.PASSWORD",url)) != NULL) {
|
||||
state->creds.password = strdup(TRIM(value));
|
||||
if(!state->creds.password) {stat = OC_ENOMEM; goto done;}
|
||||
}
|
||||
/* else ignore */
|
||||
|
||||
done:
|
||||
if(url != NULL) free(url);
|
||||
return stat;
|
||||
}
|
||||
|
||||
char*
|
||||
ocdodsrc_lookup(char* key, char* url)
|
||||
{
|
||||
int i,found;
|
||||
struct OCTriplestore* ocdodsrc = ocglobalstate.ocdodsrc;
|
||||
struct OCTriple* triple = ocdodsrc->triples;
|
||||
|
||||
if(key == NULL || ocdodsrc == NULL) return NULL;
|
||||
if(url == NULL) url = "";
|
||||
/* Assume that the triple store has been properly sorted */
|
||||
for(found=0,i=0;i<ocdodsrc->ntriples;i++,triple++) {
|
||||
int triplelen = strlen(triple->url);
|
||||
int t;
|
||||
if(strcmp(key,triple->key) != 0) continue; /* keys do not match */
|
||||
/* If the triple entry has no url, then use it (because we have checked all other cases)*/
|
||||
if(triplelen == 0) {found=1;break;}
|
||||
/* do url prefix comparison */
|
||||
t = ocstrncmp(url,triple->url,triplelen);
|
||||
if(t == 0) {found=1; break;}
|
||||
}
|
||||
if(ocdebug > 2)
|
||||
{
|
||||
if(found) {
|
||||
fprintf(stderr,"lookup %s: [%s]%s = %s\n",url,triple->url,triple->key,triple->value);
|
||||
}
|
||||
}
|
||||
return (found ? triple->value : NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ocdodsrcdump(char* msg, struct OCTriple* triples, int ntriples)
|
||||
{
|
||||
int i;
|
||||
struct OCTriplestore* ocdodsrc = ocglobalstate.ocdodsrc;
|
||||
|
||||
if(msg != NULL) fprintf(stderr,"%s\n",msg);
|
||||
if(ocdodsrc == NULL) {
|
||||
fprintf(stderr,"<EMPTY>\n");
|
||||
return;
|
||||
}
|
||||
if(triples == NULL) triples= ocdodsrc->triples;
|
||||
if(ntriples < 0 ) ntriples= ocdodsrc->ntriples;
|
||||
for(i=0;i<ntriples;i++) {
|
||||
fprintf(stderr,"\t%s\t%s\t%s\n",
|
||||
(strlen(triples[i].url)==0?"--":triples[i].url),
|
||||
triples[i].key,
|
||||
triples[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Isolate the "CURL." prefix to allow changing to something else */
|
||||
static char*
|
||||
curllookup(char* suffix, char* url)
|
||||
{
|
||||
char key[2048];
|
||||
char* value = NULL;
|
||||
strcpy(key,HTTPPREFIX);
|
||||
strcat(key,suffix);
|
||||
value = ocdodsrc_lookup(key,url);
|
||||
if(value == NULL) {
|
||||
strcpy(key,HTTPPREFIXDEPRECATED);
|
||||
strcat(key,suffix);
|
||||
value = ocdodsrc_lookup(key,url);
|
||||
}
|
||||
return value;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user