/* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc. See the COPYRIGHT file for more information. */ #include "config.h" #include #include #ifdef HAVE_SYS_STAT_H #include #endif extern int fileno(FILE*); #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,"\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;nsubnodes);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;nsubnodes);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;nsubnodes);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;isubnodes);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;natt.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;nsubnodes);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;iattributes);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;jnvalues;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;iarray.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;itree != 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 0) strlcat(line," ",llen); } 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,sizeof(line),line,5); memcpy(form.cv,n8,4); /* straight hex*/ sprintf(tmp,"%08x",form.uv); addfield(tmp,sizeof(line),line,8); if(isxdr) {swapinline32(&form.uv);} /* unsigned integer */ sprintf(tmp,"%12u",form.uv); addfield(tmp,sizeof(line),line,12); /* signed integer */ sprintf(tmp,"%12d",form.sv); addfield(tmp,sizeof(line),line,12); /* float */ sprintf(tmp,"%#g",form.fv); addfield(tmp,sizeof(line),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,sizeof(line),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,sizeof(line),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",sizeof(line),line,6); addfield("hex",sizeof(line),line,8); addfield("uint",sizeof(line),line,12); addfield("int",sizeof(line),line,12); addfield("float",sizeof(line),line,12); addfield("char[4]",sizeof(line),line,16); addfield("double",sizeof(line),line,12); strlcat(line,"\n",sizeof(line)); fprintf(stdout,"%s",line); count = (len / sizeof(int)); rem = (len % sizeof(int)); for(pmem=memory,i=0;i 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",sizeof(line),line,6); addfield("XDR (hex)",sizeof(line),line,9); addfield("!XDR (hex)",sizeof(line),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 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;ininstances;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); }