move from oc1.0 to oc2.0; create new dir oc2

This commit is contained in:
Dennis Heimbigner 2012-07-31 20:34:13 +00:00
parent 59960fcc20
commit 42999f4c7c
110 changed files with 15286 additions and 983 deletions

View File

@ -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

View File

@ -49,7 +49,7 @@ endif
# Build the opendap client?
if BUILD_DAP
OCLIB = oc
OCLIB = oc2
DAP2 = libdap2
#if BUILD_UTILITIES
NCDAPTESTDIR = ncdap_test

View File

@ -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
View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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*);

View File

@ -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

View File

@ -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.

View File

@ -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
#############################################

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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
*/

View File

@ -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;
}

View File

@ -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);

View File

@ -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"

View File

@ -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*/

View File

@ -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)

View File

@ -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*/

View File

@ -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);
}

View File

@ -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*/

View File

@ -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

View File

@ -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*/

View File

@ -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;

View File

@ -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);

View File

@ -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,")");
}

View File

@ -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*/

View File

@ -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

View File

@ -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,&currentmode);
/* 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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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}"

View File

@ -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:

View File

@ -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);
}
/** \} */

View File

@ -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*/

View File

@ -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 ...

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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 ;

View File

@ -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 ;

View File

@ -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 =

View File

@ -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 ;

View File

@ -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,

View File

@ -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 =

View File

@ -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 = _, _ ;

View File

@ -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 ;

View File

@ -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 = _, _ ;

View File

@ -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 ;

View File

@ -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 ;

View File

@ -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" ;

View File

@ -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" ;

View File

@ -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}"

View File

@ -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}"

View File

@ -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}"

View File

@ -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}"

View File

@ -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}"

View File

@ -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,

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

80
oc2/daptab.h Normal file
View 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
View 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]

1771
oc2/oc.c Normal file

File diff suppressed because it is too large Load Diff

480
oc2/oc.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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