netcdf-c/oc2/ocdump.c
Dennis Heimbigner 3db4f013bf Primary change: add dap4 support
Specific changes:
1. Add dap4 code: libdap4 and dap4_test.
   Note that until the d4ts server problem is solved, dap4 is turned off.
2. Modify various files to support dap4 flags:
	configure.ac, Makefile.am, CMakeLists.txt, etc.
3. Add nc_test/test_common.sh. This centralizes
   the handling of the locations of various
   things in the build tree: e.g. where is
   ncgen.exe located. See nc_test/test_common.sh
   for details.
4. Modify .sh files to use test_common.sh
5. Obsolete separate oc2 by moving it to be part of
   netcdf-c. This means replacing code with netcdf-c
   equivalents.
5. Add --with-testserver to configure.ac to allow
   override of the servers to be used for --enable-dap-remote-tests.
6. There were multiple versions of nctypealignment code. Try to
   centralize in libdispatch/doffset.c and include/ncoffsets.h
7. Add a unit test for the ncuri code because of its complexity.
8. Move the findserver code out of libdispatch and into
   a separate, self contained program in ncdap_test and dap4_test.
9. Move the dispatch header files (nc{3,4}dispatch.h) to
   .../include because they are now shared by modules.
10. Revamp the handling of TOPSRCDIR and TOPBUILDDIR for shell scripts.
11. Make use of MREMAP if available
12. Misc. minor changes e.g.
	- #include <config.h> -> #include "config.h"
	- Add some no-install headers to /include
	- extern -> EXTERNL and vice versa as needed
	- misc header cleanup
	- clean up checking for misc. unix vs microsoft functions
13. Change copyright decls in some files to point to LICENSE file.
14. Add notes to RELEASENOTES.md
2017-03-08 17:01:10 -07:00

683 lines
17 KiB
C

/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
See the COPYRIGHT file for more information.
*/
#include "config.h"
#include <stdlib.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.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, NCbytes* buffer)
{
int bol,len,pad;
len = ncbyteslength(buffer);
/* find preceding newline */
for(bol=len-1;;bol--) {
int c = ncbytesget(buffer,(size_t)bol);
if(c < 0) break;
if(c == '\n') {bol++; break;}
}
len = (len - bol);
pad = (pos - len);
while(pad-- > 0) ncbytescat(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<nclistlength(node->subnodes);n++) {
dumpocnode1((OCnode*)nclistget(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<nclistlength(node->subnodes);n++) {
dumpocnode1((OCnode*)nclistget(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<nclistlength(node->subnodes);n++) {
dumpocnode1((OCnode*)nclistget(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*)nclistget(node->subnodes,0),depth+2);
fprintf(stdout,"%smaps:\n",dent2(depth+1));
for(i=1;i<nclistlength(node->subnodes);i++) {
dumpocnode1((OCnode*)nclistget(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<nclistlength(node->att.values);n++) {
char* value = (char*)nclistget(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<nclistlength(node->subnodes);n++) {
dumpocnode1((OCnode*)nclistget(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<nclistlength(node->attributes);i++) {
OCattribute* att = (OCattribute*)nclistget(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 {
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*)nclistget(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;
NClist* path = nclistnew();
occollectpathtonode(ref->node,path);
for(i=0;i<nclistlength(path);i++) {
NClist* sliceset;
OCnode* node = (OCnode*)nclistget(path,i);
if(node->tree != NULL) continue; /* leave off the root node*/
fprintf(stdout,"%s%s",(i>0?PATHSEPARATOR:""),node->name);
sliceset = (NClist*)nclistget(ref->indexsets,i);
if(sliceset != NULL) {
unsigned int j;
for(j=0;j<nclistlength(sliceset);j++) {
OCslice* slice = (OCslice*)nclistget(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(size_t 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,"%6zd",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)
snprintf(stmp,sizeof(stmp),"\\%02x",c);
else
snprintf(stmp,sizeof(stmp),"%c",c);
if(!occoncat(tmp,sizeof(tmp),1,stmp))
return;
}
}
addfield(tmp,line,16);
/* double */
memcpy(dform.cv,n8,(size_t)(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 OCerror
ocreadfile(FILE* file, off_t datastart, char** memp, size_t* lenp)
{
char* mem = NULL;
size_t len;
long red;
struct stat stats;
long pos;
OCerror stat = OC_NOERR;
pos = ftell(file);
if(pos < 0) {
fprintf(stderr,"ocreadfile: ftell error.\n");
stat = OC_ERCFILE;
goto done;
}
fseek(file,0,SEEK_SET);
if(fseek(file,(long)datastart,SEEK_SET) < 0) {
fprintf(stderr,"ocreadfile: fseek error.\n");
stat = OC_ERCFILE;
goto done;
}
if(fstat(fileno(file),&stats) < 0) {
fprintf(stderr,"ocreadfile: fstat error.\n");
stat = OC_ERCFILE;
goto done;
}
len = stats.st_size;
len -= datastart;
mem = (char*)calloc(len+1,1);
if(mem == NULL) {stat = OC_ENOMEM; goto done;}
/* Read only the data part */
red = fread(mem,1,len,file);
if(red < len) {
fprintf(stderr,"ocreadfile: short file\n");
stat = OC_ERCFILE;
goto done;
}
if(fseek(file,pos,SEEK_SET) < 0) {; /* leave it as we found it*/
fprintf(stderr,"ocreadfile: fseek error.\n");
stat = OC_ERCFILE;
goto done;
}
if(memp) {*memp = mem; mem = NULL;}
if(lenp) *lenp = len;
done:
if(mem != NULL)
free(mem);
return OCTHROW(stat);
}
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)) {
/* ocreadfile allocates memory that must be freed. */
if(mem != NULL) free(mem);
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, NCbytes* buffer, int frominstance)
{
char tmp[1024];
OCnode* pattern = data->pattern;
snprintf(tmp,sizeof(tmp),"%lx:",(unsigned long)data);
ncbytescat(buffer,tmp);
if(!frominstance) {
ncbytescat(buffer," node=");
ncbytescat(buffer,pattern->name);
}
snprintf(tmp,sizeof(tmp)," xdroffset=%ld",(unsigned long)data->xdroffset);
ncbytescat(buffer,tmp);
if(data->pattern->octype == OC_Atomic) {
snprintf(tmp,sizeof(tmp)," xdrsize=%ld",(unsigned long)data->xdrsize);
ncbytescat(buffer,tmp);
}
if(ociscontainer(pattern->octype)) {
snprintf(tmp,sizeof(tmp)," ninstances=%d",(int)data->ninstances);
ncbytescat(buffer,tmp);
} else if(pattern->etype == OC_String || pattern->etype == OC_URL) {
snprintf(tmp,sizeof(tmp)," nstrings=%d",(int)data->nstrings);
ncbytescat(buffer,tmp);
}
ncbytescat(buffer," container=");
snprintf(tmp,sizeof(tmp),"%lx",(unsigned long)data->container);
ncbytescat(buffer,tmp);
ncbytescat(buffer," mode=");
ncbytescat(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, NCbytes* buffer, int depth)
{
size_t i,rank;
OCnode* pattern;
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) {
ncbytescat(buffer,header);
}
/* get info about the pattern */
pattern = data->pattern;
rank = pattern->array.rank;
/* get total dimension size */
if(rank > 0)
crossproduct = octotaldimsize(pattern->array.rank,pattern->array.sizes);
/* Dump the depth first */
snprintf(tmp,sizeof(tmp),"[%03d]",depth);
ncbytescat(buffer,tmp);
tabto(tabstops[++tabstop],buffer);
snprintf(tmp,sizeof(tmp),"%08lu",(unsigned long)data->xdroffset);
ncbytescat(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);
ncbytescat(buffer,tmp);
}
tabto(tabstops[++tabstop],buffer);
/* Dump the mode flags in compact form */
ncbytescat(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);
}
ncbytescat(buffer,tmp);
tabto(tabstops[++tabstop],buffer);
if(pattern->octype == OC_Atomic) {
typename = octypetoddsstring(pattern->etype);
} else { /*must be container*/
typename = octypetoddsstring(pattern->octype);
}
ncbytescat(buffer,typename);
tabto(tabstops[++tabstop],buffer);
if(!occopycat(tmp,sizeof(tmp),1,pattern->name))
return;
ncbytescat(buffer,tmp);
if(rank > 0) {
snprintf(tmp,sizeof(tmp),"[%lu]",(unsigned long)crossproduct);
ncbytescat(buffer,tmp);
}
ncbytescat(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, NCbytes* buffer)
{
int i;
OCdata* path[1024];
char tmp[1024];
OCdata* pathdata;
OCnode* pattern;
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];
pattern = pathdata->pattern;
ncbytescat(buffer,"/");
ncbytescat(buffer,pattern->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",(unsigned long)next->index);
ncbytescat(buffer,tmp);
}
}
if(pattern->octype == OC_Atomic) {
if(pattern->array.rank > 0) {
off_t xproduct = octotaldimsize(pattern->array.rank,pattern->array.sizes);
snprintf(tmp,sizeof(tmp),"[0..%lu]",(unsigned long)xproduct-1);
ncbytescat(buffer,tmp);
}
}
isrecord = 0;
if(pattern->octype == OC_Sequence) {
/* Is this a record or a sequence ? */
isrecord = (fisset(pathdata->datamode,OCDT_RECORD) ? 1 : 0);
}
}
/* Add suffix to path */
if(ociscontainer(pattern->octype)) {
/* add the container type, except distinguish record and sequence */
ncbytescat(buffer,":");
if(isrecord)
ncbytescat(buffer,"Record");
else
ncbytescat(buffer,octypetoddsstring(pattern->octype));
} else if(ocisatomic(pattern->octype)) {
/* add the atomic etype */
ncbytescat(buffer,":");
ncbytescat(buffer,octypetoddsstring(pattern->etype));
}
snprintf(tmp,sizeof(tmp),"->0x%0lx",(unsigned long)pathdata);
ncbytescat(buffer,tmp);
}