/********************************************************************* * Copyright 1993, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Header: /upc/share/CVS/netcdf-3/ncgen/util.c,v 1.4 2010/04/14 22:04:59 dmh Exp $ *********************************************************************/ #include "includes.h" /* Track primitive symbol instances (initialized in ncgen.y) */ Symbol* primsymbols[PRIMNO]; char* append(const char* s1, const char* s2) { int len = (s1?strlen(s1):0)+(s2?strlen(s2):0); char* result = (char*)ecalloc(len+1); result[0] = '\0'; if(s1) strcat(result,s1); if(s2) strcat(result,s2); return result; } unsigned int chartohex(char c) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return (c - '0'); case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return (c - 'A') + 0x0a; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return (c - 'a') + 0x0a; } return 0; } /* * For generated Fortran, change 'e' to 'd' in exponent of double precision * constants. */ void expe2d( char *cp) /* string containing double constant */ { char *expchar = strrchr(cp,'e'); if (expchar) { *expchar = 'd'; } } /* Returns non-zero if n is a power of 2, 0 otherwise */ int pow2( int n) { int m = n; int p = 1; while (m > 0) { m /= 2; p *= 2; } return p == 2*n; } /* * Remove trailing zeros (after decimal point) but not trailing decimal * point from ss, a string representation of a floating-point number that * might include an exponent part. */ void tztrim( char *ss /* returned string representing dd */ ) { char *cp, *ep; cp = ss; if (*cp == '-') cp++; while(isdigit((int)*cp) || *cp == '.') cp++; if (*--cp == '.') return; ep = cp+1; while (*cp == '0') cp--; cp++; if (cp == ep) return; while (*ep) *cp++ = *ep++; *cp = '\0'; return; } /* Assume bytebuffer contains pointers to char**/ void reclaimattptrs(void* buf, long count) { int i; char** ptrs = (char**)buf; for(i=0;iobjectclass) { case NG_VAR: reclaimconstlist(vsym->var.data); if(vsym->var.dims != NULL) efree(vsym->var.dims); break; case NG_ATT: if(asym->att.basetype == primsymbols[NC_STRING]) reclaimattptrs(asym->att.data,asym->att.count); else efree(asym->att.data); break; case NG_GRP: case NG_DIM: case NG_TYP: case NG_ENUM: case NG_ECONST: case NG_VLEN: case NG_STRUCT: case NG_FIELD: case NG_OPAQUE: default: break; } efree(sym->name); efree(sym); #endif } char* nctypenames[17] = { "NC_NAT", "NC_BYTE", "NC_CHAR", "NC_SHORT", "NC_INT", "NC_FLOAT", "NC_DOUBLE", "NC_UBYTE", "NC_USHORT", "NC_UINT", "NC_INT64", "NC_UINT64", "NC_STRING", "NC_VLEN", "NC_OPAQUE", "NC_ENUM", "NC_COMPOUND" }; char* nctypenamesextend[9] = { "NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT", "NC_TYPE", "NC_ECONST","NC_FIELD", "NC_ARRAY","NC_PRIM" }; char* nctypename(nc_type nctype) { char* s; if(nctype >= NC_NAT && nctype <= NC_COMPOUND) return nctypenames[nctype]; if(nctype >= NC_GRP && nctype <= NC_PRIM) return nctypenamesextend[(nctype - NC_GRP)]; if(nctype == NC_FILLVALUE) return "NC_FILL"; if(nctype == NC_NIL) return "NC_NIL"; s = poolalloc(128); sprintf(s,"NC_<%d>",nctype); return s; } /* These are the augmented NC_ values (0 based from NC_GRP)*/ char* ncclassnames[9] = { "NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT", "NC_TYP", "NC_ECONST", "NC_FIELD", "NC_ARRAY", "NC_PRIM" }; char* ncclassname(nc_class ncc) { char* s; if(ncc >= NC_NAT && ncc <= NC_COMPOUND) return nctypename((nc_type)ncc); if(ncc == NC_FILLVALUE) return "NC_FILL"; if(ncc >= NC_GRP && ncc <= NC_PRIM) return ncclassnames[ncc - NC_GRP]; s = poolalloc(128); sprintf(s,"NC_<%d>",ncc); return s; } int ncsizes[17] = { 0, 1,1,2,4, 4,8, 1,2,4, 8,8, sizeof(char*), sizeof(nc_vlen_t), 0,0,0 }; int ncsize(nc_type nctype) { if(nctype >= NC_NAT && nctype <= NC_COMPOUND) return ncsizes[nctype]; return 0; } int hasunlimited(Dimset* dimset) { int i; for(i=0;indims;i++) { Symbol* dim = dimset->dimsyms[i]; if(dim->dim.declsize == NC_UNLIMITED) return 1; } return 0; } /* return 1 if first dimension is unlimited*/ int isunlimited0(Dimset* dimset) { return (dimset->ndims > 0 && dimset->dimsyms[0]->dim.declsize == NC_UNLIMITED); } /* True only if dim[0] is unlimited all rest are bounded*/ /* or all are bounded*/ int classicunlimited(Dimset* dimset) { int i; int last = -1; for(i=0;indims;i++) { Symbol* dim = dimset->dimsyms[i]; if(dim->dim.declsize == NC_UNLIMITED) last = i; } return (last < 1); } /* True only iff no dimension is unlimited*/ int isbounded(Dimset* dimset) { int i; for(i=0;indims;i++) { Symbol* dim = dimset->dimsyms[i]; if(dim->dim.declsize == NC_UNLIMITED) return 0; } return 1; } int signedtype(nc_type nctype) { switch (nctype) { case NC_BYTE: case NC_SHORT: case NC_INT: case NC_INT64: return nctype; case NC_UBYTE: return NC_BYTE; case NC_USHORT: return NC_SHORT; case NC_UINT: return NC_INT; case NC_UINT64: return NC_INT64; default: break; } return nctype; } int unsignedtype(nc_type nctype) { switch (nctype) { case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_UINT64: return nctype; case NC_BYTE: return NC_UBYTE; case NC_SHORT: return NC_USHORT; case NC_INT: return NC_UINT; case NC_INT64: return NC_UINT64; default: break; } return nctype; } int isinttype(nc_type nctype) { return (nctype != NC_CHAR) && ((nctype >= NC_BYTE && nctype <= NC_INT) || (nctype >= NC_UBYTE && nctype <= NC_UINT64)); } int isuinttype(nc_type t) { return isinttype(t) && t >= NC_UBYTE && t <= NC_UINT64 && t != NC_INT64; } int isfloattype(nc_type nctype) { return (nctype == NC_FLOAT || nctype <= NC_DOUBLE); } int isclassicprim(nc_type nctype) { return (nctype >= NC_BYTE && nctype <= NC_DOUBLE) ; } int isclassicprimplus(nc_type nctype) { return (nctype >= NC_BYTE && nctype <= NC_DOUBLE) || (nctype == NC_STRING) ; } int isprim(nc_type nctype) { return (nctype >= NC_BYTE && nctype <= NC_STRING) ; } int isprimplus(nc_type nctype) { return (nctype >= NC_BYTE && nctype <= NC_STRING) || (nctype == NC_ECONST) || (nctype == NC_OPAQUE) ; } void collectpath(Symbol* grp, List* grpstack) { while(grp != NULL) { listpush(grpstack,(void*)grp); grp = grp->container; } } #ifdef USE_NETCDF4 /* Result is pool'd*/ char* prefixtostring(List* prefix, char* separator) { int slen=0; int plen; int i; char* result; if(prefix == NULL) return pooldup(""); plen = prefixlen(prefix); if(plen == 0) { /* root prefix*/ slen=0; /* slen += strlen(separator);*/ slen++; /* for null terminator*/ result = poolalloc(slen); result[0] = '\0'; /*strcat(result,separator);*/ } else { for(i=0;iname)); } slen++; /* for null terminator*/ result = poolalloc(slen); result[0] = '\0'; for(i=0;iname); /* append "/"*/ } } return result; } #endif /* Result is pool'd*/ char* fullname(Symbol* sym) { #ifdef USE_NETCDF4 char* s1; char* result; char* prefix; prefix = prefixtostring(sym->prefix,PATHSEPARATOR); s1 = poolcat(prefix,PATHSEPARATOR); result = poolcat(s1,sym->name); return result; #else return nulldup(sym->name); #endif } int prefixeq(List* x1, List* x2) { Symbol** l1; Symbol** l2; int len,i; if((len=listlength(x1)) != listlength(x2)) return 0; l1=(Symbol**)listcontents(x1); l2=(Symbol**)listcontents(x2); for(i=0;iname,l2[i]->name) != 0) return 0; } return 1; } List* prefixdup(List* prefix) { List* dupseq; int i; if(prefix == NULL) return listnew(); dupseq = listnew(); listsetalloc(dupseq,listlength(prefix)); for(i=0;i 0); bytes = (unsigned char*)ecalloc(blen); b = bytes; for(i=0;inext; freeSymbol(sym); sym = next; } } static void constantFree(NCConstant* con) { switch(con->nctype) { case NC_COMPOUND: /* do nothing; ReclaimDatalists below will take care of the datalist */ break; case NC_STRING: if(con->value.stringv.len > 0 && con->value.stringv.stringv != NULL) efree(con->value.stringv.stringv); break; case NC_OPAQUE: if(con->value.opaquev.len > 0 && con->value.opaquev.stringv != NULL) efree(con->value.opaquev.stringv); break; default: break; } } static void reclaimDatalists(void) { Datalist* list; NCConstant* con; /* Step 1: free up the constant content of each datalist*/ for(list=alldatalists;list != NULL; list = list->next) { if(list->data != NULL) { /* avoid multiple free attempts*/ int i; for(i=0,con=list->data;ilength;i++,con++) constantFree(con); list->data = NULL; } } /* Step 2: free up the datalist itself*/ for(list=alldatalists;list != NULL;) { Datalist* current = list; list = list->next; efree(current); } } void cleanup() { reclaimDatalists(); reclaimSymbols(); } /* compute the total n-dimensional size as 1 long array; if stop == 0, then stop = dimset->ndims. */ size_t crossproduct(Dimset* dimset, int start, int stop) { size_t totalsize = 1; int i; for(i=start;idimsyms[i]->dim.declsize; } return totalsize; } /* Do the "complement" of crossproduct; compute the total n-dimensional size of an array starting at 0 thru the 'last' array index. stop if we encounter an unlimited dimension */ size_t prefixarraylength(Dimset* dimset, int last) { return crossproduct(dimset,0,last+1); } #ifdef USE_NETCDF4 extern int H5Eprint1(FILE * stream); #endif void check_err(const int stat, const int line, const char* file) { check_err2(stat,-1,line,file); } void check_err2(const int stat, const int cdlline, const int line, const char* file) { if (stat != NC_NOERR) { if(cdlline >= 0) fprintf(stderr, "ncgen: cdl line %d; %s\n", cdlline, nc_strerror(stat)); else fprintf(stderr, "ncgen: %s\n", nc_strerror(stat)); fprintf(stderr, "\t(%s:%d)\n", file,line); #ifdef USE_NETCDF4 H5Eprint1(stderr); #endif fflush(stderr); finalize_netcdf(1); } } /** Find the index of the first unlimited dimension at or after 'start'. If no unlimited exists, return |dimset| */ int findunlimited(Dimset* dimset, int start) { for(;startndims;start++) { if(dimset->dimsyms[start]->dim.isunlimited) return start; } return dimset->ndims; } /** Find the index of the last unlimited dimension. If no unlimited exists, return |dimset| */ int findlastunlimited(Dimset* dimset) { int i; for(i=dimset->ndims-1;i>=0;i--) { if(dimset->dimsyms[i]->dim.isunlimited) return i; } return dimset->ndims; } /** Count the number of unlimited dimensions. */ int countunlimited(Dimset* dimset) { int i, count; for(count=0,i=dimset->ndims-1;i>=0;i--) { if(dimset->dimsyms[i]->dim.isunlimited) count++; } return count; } /* Return standard format string */ const char * kind_string(int kind) { switch (kind) { case 1: return "classic"; case 2: return "64-bit offset"; case 3: return "netCDF-4"; case 4: return "netCDF-4 classic model"; default: derror("Unknown format index: %d\n",kind); } return NULL; } #ifdef USE_NETCDF4i nt getrootid(int grpid) { int current = grpid; int parent = current; /* see if root id */ for(;;) { int stat = nc_inq_grp_parent(current,&parent); if(stat) break; current = parent; } return current; } #endif