/********************************************************************* * Copyright 2018, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Header: /upc/share/CVS/netcdf-3/ncgen/gencml.c,v 1.5 2010/04/04 19:39:46 dmh Exp $ *********************************************************************/ #include "includes.h" #include /* for isprint() */ #ifdef ENABLE_CML #undef TRACE extern List* vlenconstants; /* List;*/ /* Forward */ /* static const char* ncstype(nc_type); static const char* nctype(nc_type); static const char* ncctype(nc_type); static const char* groupncid(Symbol*); static const char* typencid(Symbol*); static const char* varncid(Symbol*); static const char* dimncid(Symbol*); */ static void gencml_group(Symbol* group); static char* ncxtype(nc_type type); #ifdef USE_NETCDF4 static void definextype(Symbol*); static char* xprefixed(List* prefix, char* suffix, char* separator); static void definespecialattributes(Symbol* vsym); #endif static void defineattribute(Symbol* asym); static void definevardata(Symbol*); #ifdef USE_NETCDF4 static void xprint(Bytebuffer* buf); #endif static void xpartial(char* line); static void xline(char* line); static void xflush(void); /* Global Bytebuffer into which to store the C code output; periodically dumped to file by xflush(). */ Bytebuffer* xcode; /* * Generate C code for creating netCDF from in-memory structure. */ void gencml_netcdf(void) { xcode = bbNew(); bbSetalloc(xcode,C_MAX_STMT); const char *filename = rootgroup->file.filename; /* Dump XML header */ xline(""); xline(""); xline(""); xline(""); xline(""); xflush(); /* Recursively dump all groups via the rootgroup */ gencml_group(rootgroup); } void gencml_close(void) { xline(""); xflush(); } static void gencml_group(Symbol* group) { int idim, ivar, iatt; int ndims, nvars, natts, ngatts, ngrps, ntyps; #ifdef USE_NETCDF4 int igrp,ityp; #endif ndims = listlength(dimdefs); nvars = listlength(vardefs); natts = listlength(attdefs); ngatts = listlength(gattdefs); ngrps = listlength(grpdefs); ntyps = listlength(typdefs); #ifdef USE_NETCDF4 if(group != rootgroup) { xline(""); xpartial(""); } #endif #ifdef USE_NETCDF4 /* Construct code to define types*/ if(ntyps > 0) { xline(""); xline(""); for(ityp = 0; ityp < ntyps; ityp++) { Symbol* tsym = (Symbol*)listget(typdefs,ityp); xline(""); if(tsym->subclass == NC_PRIM || tsym->subclass == NC_ARRAY) continue;/*no need to do these*/ definextype(tsym); } xline(""); xline(""); } xflush(); #endif /* define dimensions from info in dims array */ if (ndims > 0) { xline(""); xline(""); for(idim = 0; idim < ndims; idim++) { Symbol* dsym = (Symbol*)listget(dimdefs,idim); unsigned long declsize = dsym->dim.size; char* utag = ""; if(declsize == 0) utag = " isUnlimited=\"true\""; nprintf(stmt,sizeof(stmt), "", xname(dsym),declsize,utag); xline(stmt); } } xflush(); /* Define the global attributes*/ if(ngatts > 0) { xline(""); xline(""); for(iatt = 0; iatt < ngatts; iatt++) { Symbol* gasym = (Symbol*)listget(gattdefs,iatt); if(gasym->att.var == NULL) /* => global */ defineattribute(gasym); } xline(""); } xflush(); /* define variables from info in vars array */ if (nvars > 0) { xline(""); xline(""); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); Dimset* dimset = &vsym->typ.dimset; if(ivar > 0) xline(""); nprintf(stmt,sizeof(stmt),"ndims > 0) { xpartial(" shape=\""); for(idim = 0; idim < dimset->ndims; idim++) { Symbol* dsym = dimset->dimsyms[idim]; if(idim > 0) xpartial(" "); xpartial(xname(dsym)); } xpartial("\""); } xpartial(" type=\""); xpartial(xname(vsym->typ.basetype)); xline(" >"); #ifdef USE_NETCDF4 definespecialattributes(vsym); #endif /*USE_NETCDF4*/ if(natts > 0) { for(iatt = 0; iatt < natts; iatt++) { Symbol* asym = (Symbol*)listget(attdefs,iatt); if(asym->att.var == vsym) defineattribute(asym); } } if(vsym->data != NULL) definevardata(vsym); xline(""); } } xflush(); #ifdef USE_NETCDF4 /* Recursively define subgroups */ for(igrp=0;igrpcontainer != group) continue; gencml_group(gsym); } #endif #ifdef USE_NETCDF4 if(group != rootgroup) { xline(""); } #endif } #ifdef USE_NETCDF4 static void definespecialattributes(Symbol* vsym) { Specialdata* special = &vsym->var.special; if(usingclassic) return; if(special->flags & _STORAGE_FLAG) { int storage = special->_Storage; size_t* chunks = special->_ChunkSizes; nprintf(stmt,sizeof(stmt),"nchunks != 0 && chunks != NULL) { int i; xpartial(" value=\""); for(i=0;inchunks;i++) { if(i > 0) xpartial(" "); nprintf(stmt,sizeof(stmt),"%ld",special->_ChunkSizes[i]); xpartial(stmt); } xpartial("\""); } xline(" />"); } if(special->flags & _FLETCHER32_FLAG) { nprintf(stmt,sizeof(stmt), "", (special->_Fletcher32?"true":"false")); xline(stmt); } if(special->flags & (_DEFLATE_FLAG | _SHUFFLE_FLAG)) { nprintf(stmt,sizeof(stmt), "", (special->_Shuffle==1?"shuffle":"noshuffle"), (special->_DeflateLevel >= 0?"true":"false"), (special->_DeflateLevel >= 0?special->_DeflateLevel:0)); xline(stmt); } if(special->flags & _ENDIAN_FLAG) { nprintf(stmt,sizeof(stmt), "", (special->_Endianness == NC_ENDIAN_LITTLE?"little":"big")); xline(stmt); } if(special->flags & _NOFILL_FLAG) { nprintf(stmt,sizeof(stmt), "", (special->_Fill?"fill":"nofill")); xline(stmt); } } static void definextype(Symbol* tsym) { int i; ASSERT(tsym->objectclass == NC_TYPE); switch (tsym->subclass) { case NC_PRIM: break; /* these are already taken care of*/ case NC_OPAQUE: nprintf(stmt,sizeof(stmt),"", xname(tsym),(unsigned long)tsym->typ.size); xline(stmt); break; case NC_ENUM: nprintf(stmt,sizeof(stmt),"", xname(tsym),xtypename(tsym->typ.basetype)); xline(stmt); stmt[0] = 0; for(i=0;isubnodes);i++) { Symbol* econst = (Symbol*)listget(tsym->subnodes,i); ASSERT(econst->subclass == NC_ECONST); nprintf(stmt,sizeof(stmt),"", xname(econst), xconst(econst->typ.econst)); xline(stmt); } xline(""); break; case NC_VLEN: nprintf(stmt,sizeof(stmt),"", xname(tsym),xtypename(tsym)); xline(stmt); break; case NC_COMPOUND: nprintf(stmt,sizeof(stmt),"", xname(tsym)); xline(stmt); for(i=0;isubnodes);i++) { Symbol* efield = (Symbol*)listget(tsym->subnodes,i); ASSERT(efield->subclass == NC_FIELD); nprintf(stmt,sizeof(stmt),"typ.dimset.ndims > 0) { Bytebuffer* dimbuf = bbNew(); int j; bbCat(dimbuf," shape=\""); for(j=0;jtyp.dimset.ndims;j++) { char tmp[32]; Symbol* dim; if(j > 0) bbCat(dimbuf," "); dim = efield->typ.dimset.dimsyms[j]; ASSERT(dim->dim.isconstant); snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)dim->dim.size); bbCat(dimbuf,tmp); } bbCat(dimbuf,"\""); xprint(dimbuf); bbFree(dimbuf); } nprintf(stmt,sizeof(stmt)," type=\"%s\" />", xtypename(efield->typ.basetype)); xline(stmt); } xline(""); xflush(); break; case NC_ARRAY: /* ignore: this will be handled by def_var*/ break; default: panic("definextype: unexpected type subclass: %d",tsym->subclass); } } #endif /*USE_NETCDF4*/ static void defineattribute(Symbol* asym) { unsigned long len; Datalist* list; Symbol* basetype = asym->typ.basetype; Bytebuffer* code = NULL; /* capture other decls*/ list = asym->data; if(list == NULL) PANIC("empty attribute list"); len = asym->att.count; if(len == 0) PANIC("empty attribute list"); code = bbNew(); gencml_attrdata(asym,code); /* Handle NC_CHAR specially */ if(basetype->typ.typecode == NC_CHAR) { /* revise the length count */ len = bbLength(code); if(len == 0) {bbAppend(code,'\0'); len++;} xquotestring(code); } if(isprimplus(basetype->typ.typecode)) { nprintf(stmt,sizeof(stmt),"", xname(asym),xtypename(asym->typ.basetype), bbContents(code)); xline(stmt); } else { nprintf(stmt,sizeof(stmt),"", xname(asym),xtypename(asym->typ.basetype)); xline(stmt); xpartial(""); xpartial(bbContents(code)); xline(""); xline(""); } xflush(); } /* Note: no closure is used for CML */ static void definevardata(Symbol* vsym) { Dimset* dimset = &vsym->typ.dimset; int isscalar = (dimset->ndims == 0); Bytebuffer* code; nc_type typecode = vsym->typ.basetype->typ.typecode; if(vsym->data == NULL) return; code = bbNew(); /* Handle special cases first*/ if(isscalar) { gencml_scalardata(vsym,code); } else { /* Non-scalar*/ gencml_arraydata(vsym,code); } if(typecode == NC_STRING) { xpartial(""); xpartial(bbContents(code)); xline(""); } else { xline(""); xpartial(bbContents(code)); if(isprimplus(vsym->typ.basetype->typ.typecode)) xline(""); xline(""); } bbFree(code); } /* return CML name for netCDF type, given type code */ static char * ncxtype(nc_type type) /* netCDF type code */ { switch (type) { case NC_CHAR: return "char"; case NC_BYTE: return "byte"; case NC_SHORT: return "short"; case NC_INT: return "int"; case NC_FLOAT: return "float"; case NC_DOUBLE: return "double"; case NC_UBYTE: return "ubyte"; case NC_USHORT: return "ushort"; case NC_UINT: return "uint"; case NC_INT64: return "int64"; case NC_UINT64: return "uint64"; case NC_STRING: return "string"; default: PANIC("nctype: bad type code"); } return NULL; } /* Compute the CML name for a given type*/ char* xtypename(Symbol* tsym) { char* name; ASSERT(tsym->objectclass == NC_TYPE); if(tsym->subclass == NC_PRIM) name = ncxtype(tsym->typ.typecode); else name = xname(tsym); return name; } /* Compute the CML name for a given symbol*/ /* Cache in symbol->lname*/ char* xname(Symbol* sym) { if(sym->lname == NULL) { char* name = pooldup(sym->name); #ifdef USE_NETCDF4 if(sym->subclass == NC_FIELD || sym->subclass == NC_ECONST) { sym->lname = nulldup(codify(name)); } else sym->lname = nulldup(codify(xprefixed(sym->prefix,name,"/"))); #else sym->lname = nulldup(codify(name)); /* convert to usable form*/ #endif } return sym->lname; } #ifdef USE_NETCDF4 /* Result is pool alloc'd*/ static char* xprefixed(List* prefix, char* suffix, char* separator) { int slen; int plen; int i; char* result; ASSERT(suffix != NULL); plen = prefixlen(prefix); if(prefix == NULL || plen == 0) return codify(suffix); /* plen > 0*/ slen = 0; for(i=0;iname)+strlen(separator)); } slen += strlen(suffix); slen++; /* for null terminator*/ result = poolalloc(slen); result[0] = '\0'; /* Leave off the root*/ i = (rootgroup == (Symbol*)listget(prefix,0))?1:0; for(;iname); /* append ""*/ strcat(result,separator); } strcat(result,suffix); /* append ""*/ return result; } #endif /**************************************************/ /* * Output a CML statement */ #ifdef USE_NETCDF4 static void xprint(Bytebuffer* buf) { bbAppendn(xcode,bbContents(buf),bbLength(buf)); } #endif static void xpartial(char* line) { bbCat(xcode,line); } static void xline(char* line) { xpartial(line); bbCat(xcode,"\n"); } static void xflush(void) { if(bbLength(xcode) > 0) { bbAppend(xcode,'\0'); fputs(bbContents(xcode),stdout); fflush(stdout); bbClear(xcode); } } #endif /*ENABLE_CML*/