/********************************************************************* * Copyright 1993, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Header: /upc/share/CVS/netcdf-3/ncgen/genbin.c,v 1.4 2010/05/27 21:34:17 dmh Exp $ *********************************************************************/ #include /* for isprint() */ #include "includes.h" #include "nciter.h" #include "offsets.h" #ifdef ENABLE_BINARY #undef TRACE extern List* vlenconstants; /* Forward*/ static void genbin_defineattr(Symbol* asym,Bytebuffer*); static void genbin_definevardata(Symbol* vsym); static void genbin_write(Symbol*,Bytebuffer*,Odometer*,int); #ifdef USE_NETCDF4 static void genbin_deftype(Symbol* tsym); static void genbin_definespecialattributes(Symbol* var); #endif /* * Generate C code for creating netCDF from in-memory structure. */ void gen_netcdf(const char *filename) { int stat, ncid; int idim, ivar, iatt; int ndims, nvars, natts, ngatts, ntyps, ngrps; #ifdef USE_NETCDF4 int igrp; #endif Bytebuffer* databuf = bbNew(); ndims = listlength(dimdefs); nvars = listlength(vardefs); natts = listlength(attdefs); ngatts = listlength(gattdefs); ntyps = listlength(typdefs); ngrps = listlength(grpdefs); /* create netCDF file, uses NC_CLOBBER mode */ cmode_modifier |= NC_CLOBBER; #ifdef USE_NETCDF4 if(!usingclassic) cmode_modifier |= NC_NETCDF4; #endif stat = nc_create(filename, cmode_modifier, &ncid); check_err(stat,__LINE__,__FILE__); /* ncid created above is also root group*/ rootgroup->ncid = ncid; #ifdef USE_NETCDF4 /* Define the group structure */ /* walking grdefs list will do a preorder walk of all defined groups*/ for(igrp=0;igrpcontainer->ncid,gsym->name,&gsym->ncid); check_err(stat,__LINE__,__FILE__); } #endif #ifdef USE_NETCDF4 /* Define the types*/ if (ntyps > 0) { int ityp; for(ityp = 0; ityp < ntyps; ityp++) { Symbol* tsym = (Symbol*)listget(typdefs,ityp); genbin_deftype(tsym); } } #endif /* define dimensions from info in dims array */ if (ndims > 0) { for(idim = 0; idim < ndims; idim++) { Symbol* dsym = (Symbol*)listget(dimdefs,idim); stat = nc_def_dim(dsym->container->ncid, dsym->name, dsym->dim.declsize, &dsym->ncid); check_err(stat,__LINE__,__FILE__); } } /* define variables from info in vars array */ if (nvars > 0) { for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); if (vsym->typ.dimset.ndims > 0) { /* a dimensioned variable */ /* construct a vector of dimension ids*/ int dimids[NC_MAX_VAR_DIMS]; for(idim=0;idimtyp.dimset.ndims;idim++) dimids[idim] = vsym->typ.dimset.dimsyms[idim]->ncid; stat = nc_def_var(vsym->container->ncid, vsym->name, vsym->typ.basetype->ncid, vsym->typ.dimset.ndims, dimids, &vsym->ncid); } else { /* a scalar */ stat = nc_def_var(vsym->container->ncid, vsym->name, vsym->typ.basetype->ncid, vsym->typ.dimset.ndims, NULL, &vsym->ncid); } check_err(stat,__LINE__,__FILE__); } } #ifdef USE_NETCDF4 /* Collect vlen data*/ bindata_vlenconstants(vlenconstants); /* define special variable properties */ if(nvars > 0) { for(ivar = 0; ivar < nvars; ivar++) { Symbol* var = (Symbol*)listget(vardefs,ivar); genbin_definespecialattributes(var); } } #endif /*USE_NETCDF4*/ /* define global attributes */ if(ngatts > 0) { for(iatt = 0; iatt < ngatts; iatt++) { Symbol* gasym = (Symbol*)listget(gattdefs,iatt); bbClear(databuf); genbin_defineattr(gasym,databuf); } } /* define per-variable attributes */ if(natts > 0) { for(iatt = 0; iatt < natts; iatt++) { Symbol* asym = (Symbol*)listget(attdefs,iatt); bbClear(databuf); genbin_defineattr(asym,databuf); } } if (nofill_flag) { stat = nc_set_fill(rootgroup->ncid, NC_NOFILL, 0); check_err(stat,__LINE__,__FILE__); } /* leave define mode */ stat = nc_enddef(rootgroup->ncid); check_err(stat,__LINE__,__FILE__); /* Load values into those variables with defined data */ if(nvars > 0) { for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); if(vsym->data != NULL) { bbClear(databuf); genbin_definevardata(vsym); } } } bbFree(databuf); } #ifdef USE_NETCDF4 static void genbin_definespecialattributes(Symbol* var) { int stat; Specialdata* special = &var->var.special; if(special->flags & _STORAGE_FLAG) { int storage = special->_Storage; size_t* chunks = special->_ChunkSizes; if(special->nchunks == 0 || chunks == NULL) chunks = NULL; stat = nc_def_var_chunking(var->container->ncid, var->ncid, (storage == NC_CONTIGUOUS?NC_CONTIGUOUS :NC_CHUNKED), chunks); check_err(stat,__LINE__,__FILE__); } if(special->flags & _FLETCHER32_FLAG) { stat = nc_def_var_fletcher32(var->container->ncid, var->ncid, special->_Fletcher32); check_err(stat,__LINE__,__FILE__); } if(special->flags & (_DEFLATE_FLAG | _SHUFFLE_FLAG)) { stat = nc_def_var_deflate(var->container->ncid, var->ncid, (special->_Shuffle == 1?1:0), (special->_DeflateLevel >= 0?1:0), (special->_DeflateLevel >= 0?special->_DeflateLevel :0)); check_err(stat,__LINE__,__FILE__); } if(special->flags & _ENDIAN_FLAG) { stat = nc_def_var_endian(var->container->ncid, var->ncid, (special->_Endianness == NC_ENDIAN_LITTLE? NC_ENDIAN_LITTLE :NC_ENDIAN_BIG)); check_err(stat,__LINE__,__FILE__); } if(special->flags & _NOFILL_FLAG) { stat = nc_def_var_fill(var->container->ncid, var->ncid, (special->_Fill?NC_FILL:NC_NOFILL), NULL); check_err(stat,__LINE__,__FILE__); } } #endif /*USE_NETCDF4*/ void cl_netcdf(void) { int stat; stat = nc_close(rootgroup->ncid); check_err(stat,__LINE__,__FILE__); } #ifdef USE_NETCDF4 /* Generate type definitions */ static void genbin_deftype(Symbol* tsym) { int i,stat; ASSERT(tsym->objectclass == NC_TYPE); switch (tsym->subclass) { case NC_PRIM: break; /* these are already taken care of*/ case NC_OPAQUE: stat = nc_def_opaque(tsym->container->ncid, tsym->typ.size, tsym->name, &tsym->ncid); check_err(stat,__LINE__,__FILE__); break; case NC_ENUM: { Bytebuffer* datum; Datalist* ecdl; Datasrc* esrc; stat = nc_def_enum(tsym->container->ncid, tsym->typ.basetype->typ.typecode, tsym->name, &tsym->ncid); check_err(stat,__LINE__,__FILE__); datum = bbNew(); ecdl = builddatalist(1); dlextend(ecdl); /* make room for one constant*/ ecdl->length = 1; esrc = datalist2src(ecdl); for(i=0;isubnodes);i++) { Symbol* econst = (Symbol*)listget(tsym->subnodes,i); ASSERT(econst->subclass == NC_ECONST); ecdl->data[0] = econst->typ.econst; esrc->index = 0; bbClear(datum); bindata_basetype(econst->typ.basetype,esrc,datum,NULL); stat = nc_insert_enum(tsym->container->ncid, tsym->ncid, econst->name, bbContents(datum)); check_err(stat,__LINE__,__FILE__); } bbFree(datum); ecdl->length = 0; freedatasrc(esrc); } break; case NC_VLEN: stat = nc_def_vlen(tsym->container->ncid, tsym->name, tsym->typ.basetype->ncid, &tsym->ncid); check_err(stat,__LINE__,__FILE__); break; case NC_COMPOUND: stat = nc_def_compound(tsym->container->ncid, tsym->typ.size, tsym->name, &tsym->ncid); check_err(stat,__LINE__,__FILE__); for(i=0;isubnodes);i++) { Symbol* efield = (Symbol*)listget(tsym->subnodes,i); ASSERT(efield->subclass == NC_FIELD); if(efield->typ.dimset.ndims == 0){ stat = nc_insert_compound( tsym->container->ncid, tsym->ncid, efield->name, efield->typ.offset, efield->typ.basetype->ncid); } else { int j; Bytebuffer* dimbuf = bbNew(); /* Generate the field dimension constants*/ for(j=0;jtyp.dimset.ndims;j++) { unsigned int size = efield->typ.dimset.dimsyms[j]->dim.declsize; bbAppendn(dimbuf,(char*)&size,sizeof(size)); } stat = nc_insert_array_compound( tsym->container->ncid, tsym->ncid, efield->name, efield->typ.offset, efield->typ.basetype->ncid, efield->typ.dimset.ndims, (int*)bbContents(dimbuf)); bbFree(dimbuf); } check_err(stat,__LINE__,__FILE__); } break; default: panic("definectype: unexpected type subclass"); } } #endif /*USE_NETCDF4*/ static void genbin_defineattr(Symbol* asym,Bytebuffer* databuf) { int stat; size_t len; Datalist* list; int varid, grpid, typid; Symbol* basetype = asym->typ.basetype; bbClear(databuf); grpid = asym->container->ncid, varid = (asym->att.var == NULL?NC_GLOBAL : asym->att.var->ncid); typid = basetype->ncid; list = asym->data; len = list->length; bindata_attrdata(asym,databuf); /* Use the specialized put_att_XX routines if possible*/ if(isprim(basetype->typ.typecode)) { switch (basetype->typ.typecode) { case NC_BYTE: { signed char* data = (signed char*)bbContents(databuf); stat = nc_put_att_schar(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_CHAR: { char* data = (char*)bbContents(databuf); size_t slen = bbLength(databuf); #ifdef IGNORE /* Revise length if slen == 0 */ if(slen == 0) {bbAppend(databuf,'\0'); slen++;} #endif stat = nc_put_att_text(grpid,varid,asym->name,slen,data); check_err(stat,__LINE__,__FILE__); } break; case NC_SHORT: { short* data = (short*)bbContents(databuf); stat = nc_put_att_short(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_INT: { int* data = (int*)bbContents(databuf); stat = nc_put_att_int(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_FLOAT: { float* data = (float*)bbContents(databuf); stat = nc_put_att_float(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_DOUBLE: { double* data = (double*)bbContents(databuf); stat = nc_put_att_double(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; #ifdef USE_NETCDF4 case NC_STRING: { const char** data; data = (const char**)bbContents(databuf); stat = nc_put_att_string(grpid,varid,asym->name, bbLength(databuf)/sizeof(char*), data); } break; case NC_UBYTE: { unsigned char* data = (unsigned char*)bbContents(databuf); stat = nc_put_att_uchar(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_USHORT: { unsigned short* data = (unsigned short*)bbContents(databuf); stat = nc_put_att_ushort(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_UINT: { unsigned int* data = (unsigned int*)bbContents(databuf); stat = nc_put_att_uint(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_INT64: { long long* data = (long long*)bbContents(databuf); stat = nc_put_att_longlong(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; case NC_UINT64: { unsigned long long* data = (unsigned long long*)bbContents(databuf); stat = nc_put_att_ulonglong(grpid,varid,asym->name,typid,len,data); check_err(stat,__LINE__,__FILE__); } break; #endif default: PANIC1("genbin_defineattr: unexpected basetype: %d",basetype->typ.typecode); } } else { /* use the generic put_attribute for user defined types*/ const char* data; char out[4096]; data = (const char*)bbContents(databuf); stat = nc_put_att(grpid,varid,asym->name,typid, len,(void*)data); check_err(stat,__LINE__,__FILE__); memset(out,0x77,sizeof(out)); stat = nc_get_att(grpid,varid,asym->name,&out); check_err(stat,__LINE__,__FILE__); } } /* Following is patterned after the walk functions in semantics.c */ static void genbin_definevardata(Symbol* vsym) { int varid, grpid; int rank; Bytebuffer* memory; nciter_t iter; Odometer* odom = NULL; size_t nelems; int chartype = (vsym->typ.basetype->typ.typecode == NC_CHAR); Datalist* fillsrc = vsym->var.special._Fillvalue; int isscalar = (vsym->typ.dimset.ndims == 0); grpid = vsym->container->ncid, varid = vsym->ncid; rank = vsym->typ.dimset.ndims; memory = bbNew(); /* give the buffer a running start to be large enough*/ bbSetalloc(memory, nciterbuffersize); if(vsym->data == NULL) return; /* Generate character constants separately */ if(!isscalar && chartype) { gen_chararray(vsym,memory,fillsrc); /* generate a corresponding odometer */ odom = newodometer(&vsym->typ.dimset,NULL,NULL); genbin_write(vsym,memory,odom,0); } else { /* not character constant */ Datasrc* src = datalist2src(vsym->data); if(isscalar) { /*scalar */ bindata_basetype(vsym->typ.basetype,src,memory,fillsrc); /*scalar*/ if(bbLength(memory) > 0) genbin_write(vsym,memory,odom,1); } else { /* This is the heavy lifing */ /* Create an iterator to generate blocks of data */ nc_get_iter(vsym,nciterbuffersize,&iter); /* Fill in the local odometer instance */ odom = newodometer(&vsym->typ.dimset,NULL,NULL); for(;;) { nelems=nc_next_iter(&iter,odom->start,odom->count); if(nelems == 0) break; if(debug > 0) {/*dump the iteration info*/ int i; fprintf(stderr,"iter: %s->start[",vsym->name); for(i=0;irank;i++) fprintf(stderr,"%s%lu",(i==0?"":","),(unsigned long)odom->start[i]); fprintf(stderr,"]\n %s->count[",vsym->name); for(i=0;irank;i++) fprintf(stderr,"%s%lu",(i==0?"":","),(unsigned long)odom->count[i]); fprintf(stderr,"]\n"); } bindata_array(vsym,memory,src,odom,/*index=*/0,fillsrc); /* Dump this chunk of (non-scalar) memory */ genbin_write(vsym,memory,odom,0); } /* Write any residual data */ if(bbLength(memory) > 0) genbin_write(vsym,memory,odom,0); } } odometerfree(odom); bbFree(memory); } static void genbin_write(Symbol* vsym, Bytebuffer* memory, Odometer* odom, int scalar) { int stat = NC_NOERR; if(!scalar && debug > 0) { int i; fprintf(stderr,"startset = ["); for(i=0;irank;i++) fprintf(stderr,"%s%lu",(i>0?", ":""),(unsigned long)odom->start[i]); fprintf(stderr,"] "); fprintf(stderr,"countset = ["); for(i=0;irank;i++) fprintf(stderr,"%s%lu",(i>0?", ":""),(unsigned long)odom->count[i]); fprintf(stderr,"]\n"); fflush(stderr); } if(scalar) { size_t count[1] = {1}; stat = nc_put_var1(vsym->container->ncid, vsym->ncid, count, bbContents(memory)); } else { stat = nc_put_vara(vsym->container->ncid, vsym->ncid, odom->start, odom->count, bbContents(memory)); } check_err(stat,__LINE__,__FILE__); bbClear(memory); } #endif /*ENABLE_BINARY*/