/********************************************************************* * Copyright 2018, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Header: /upc/share/CVS/netcdf-3/ncgen/genjjni.c,v 1.6 2010/04/04 19:39:46 dmh Exp $ *********************************************************************/ #include "includes.h" #ifdef ENABLE_JAVA #undef JGDB #undef TRACE /*MNEMONIC*/ #define USEMEMORY 1 extern List* vlenconstants; /* List;*/ /* Forward */ static void genjjni_definevardata(Symbol* vsym); static void genjjni_primattribute(Symbol*, Bytebuffer*, unsigned long); static void genjjni_scalarprim(Symbol* var, Bytebuffer* code); static const char* jgroupncid(Symbol*); static const char* jtypencid(Symbol*); static const char* jvarncid(Symbol*); static const char* jdimncid(Symbol*); #ifdef USE_NETCDF4 static void definejtype(Symbol*); static char* jprefixed(List* prefix, char* suffix, char* separator); static void genjjni_deftype(Symbol*); static void definespecialattributes(Symbol* vsym); #endif static int jputvaraprim(Putvar*, Odometer*, Bytebuffer*, size_t*); static void genjjni_defineattribute(Symbol* asym); static void genjjni_definevardata(Symbol*); static void computemaxunlimited(void); /* Global Bytebuffer into which to store the C code output; periodically dumped to file by jflush(). Defined in genjstd.c. */ extern Bytebuffer* jcode; /* * Generate code for creating netCDF from in-memory structure. */ void gen_ncjava_jni(const char *filename) { int idim, ivar, iatt, maxdims; int ndims, nvars, natts, ngatts, ngrps, ntyps; char* cmode_string; #ifdef USE_NETCDF4 int igrp,ityp; #endif jcode = bbNew(); bbSetalloc(jcode,C_MAX_STMT); ndims = listlength(dimdefs); nvars = listlength(vardefs); natts = listlength(attdefs); ngatts = listlength(gattdefs); ngrps = listlength(grpdefs); ntyps = listlength(typdefs); /* Construct the main class */ #ifdef JGDB jline("import java.io.*;"); #endif jline("import java.util.*;"); jline("import netcdf.*;"); jline("import static netcdf.Constants.*;"); jline("import static netcdf.Netcdf.*;"); jline(""); jpartial("public class "); jline(mainname); jline("{"); /* Do static initializations */ jline(""); jline("static {"); jlined(1,"System.loadLibrary(\"ncjni\");"); jlined(1,"Netcdf.init();"); jline("}"); jline(""); jline("static long memory = Memory.create(); /* For storing data */"); #ifdef USE_NETCDF4 if (ntyps > 0) { for(ityp = 0; ityp < ntyps; ityp++) { Symbol* tsym = (Symbol*)listget(typdefs,ityp); definejtype(tsym); } bbCat(jcode,""); } jflush(); /* Define vlen constants; For java, this is done in two parts. Part 1 (here) defines the constants and part 2 fills them in. */ { jflush(); /* dump code to this point*/ genjjni_vlenconstants(vlenconstants,jcode); jline(""); } /* Construct the chunking constants*/ if(!usingclassic) { for(ivar=0;ivarvar.special; if(special->flags & _CHUNKSIZE_FLAG) { int i; size_t* chunks = special->_ChunkSizes; if(special->nchunks == 0 || chunks == NULL) continue; bbClear(tmp); for(i=0;inchunks;i++) { nprintf(stmt,sizeof(stmt),"%s%ld", (i == 0?"":", "),special->_ChunkSizes[i]); bbCat(tmp,stmt); } nprintf(stmt,sizeof(stmt),"static final long[] %s_chunksizes = {", jname(var),special->nchunks); jpartial(stmt); jprint(tmp); jline("} ;"); } } jline(""); } #endif /*USE_NETCDF4*/ jline("static public void"); jline("check_err(int stat) throws Exception"); jline("{"); jlined(1,"if (stat != NC_NOERR) {"); jlined(2,"System.err.println(\"Failed: \"+nc_strerror(stat));"); jlined(2,"throw new Exception(nc_strerror(stat));"); jlined(1,"}"); jline("}"); jline(""); /* Now construct the main procedure*/ jline("static public void main(String[] argv) throws Exception"); nprintf(stmt,sizeof(stmt), "{ /* create %s */",filename); jline(stmt); /* create necessary declarations */ jline(""); jlined(1,"int stat; /* return status */"); jlined(1,"int ncid; /* netCDF id */"); jlined(1,"int[] ncidp = new int[1]; /* netCDF id return */"); jflush(); /* Define vlen constants Part 2. The idea is to walk all the data lists whose variable type has a vlen and collect the vlen data and define a constant for it. */ jline(""); jflush(); /* dump code to this point*/ genjjni_vlendata(vlenconstants,jcode); #ifdef JGDB jline("{"); jline("System.out.print(\"go?\");"); jline("BufferedReader rin = new BufferedReader(new InputStreamReader(System.in));"); jline("rin.readLine();"); jline("}"); #endif #ifdef USE_NETCDF4 /* Define variables to hold group ids*/ if(!usingclassic) { jline(""); jlined(1,"/* group ids */"); } if(!usingclassic && ngrps > 0) { for(igrp = 0; igrp < ngrps; igrp++) { Symbol* gsym = (Symbol*)listget(grpdefs,igrp); nprintf(stmt,sizeof(stmt),"int %s;",jgroupncid(gsym)); jlined(1,stmt); } } /* define variables to hold type ids*/ if(!usingclassic && ntyps > 0) { jline(""); jlined(1,"/* type ids */"); for(ityp = 0; ityp < ntyps; ityp++) { Symbol* tsym = (Symbol*)listget(typdefs,ityp); nprintf(stmt,sizeof(stmt),"int %s;",jtypencid(tsym)); jlined(1,stmt); } } jflush(); #endif if (ndims > 0) { jline(""); jlined(1,"/* dimension ids */"); for(idim = 0; idim < ndims; idim++) { Symbol* dsym = (Symbol*)listget(dimdefs,idim); nprintf(stmt,sizeof(stmt),"int %s;",jdimncid(dsym)); jlined(1,stmt); } jline(""); jlined(1,"/* dimension lengths */"); for(idim = 0; idim < ndims; idim++) { Symbol* dsym = (Symbol*)listget(dimdefs,idim); if (dsym->dim.size == NC_UNLIMITED) { nprintf(stmt,sizeof(stmt),"%sfinal long %s_len = NC_UNLIMITED;", indented(1),jname(dsym)); } else { nprintf(stmt,sizeof(stmt),"%sfinal long %s_len = %lu;", indented(1), jname(dsym), (unsigned long) dsym->dim.size); } jline(stmt); } } jflush(); maxdims = 0; /* most dimensions of any variable */ for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); if(vsym->typ.dimset.ndims > maxdims) maxdims = vsym->typ.dimset.ndims; } if (nvars > 0) { jline(""); jlined(1,"/* variable ids */"); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); nprintf(stmt,sizeof(stmt),"int %s;", jvarncid(vsym)); jlined(1,stmt); } jline(""); jlined(1,"/* rank (number of dimensions) for each variable */"); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); nprintf(stmt,sizeof(stmt),"final int RANK_%s = %d;", jname(vsym),vsym->typ.dimset.ndims); jlined(1,stmt); } if (maxdims > 0) { /* we have dimensioned variables */ jline(""); jlined(1,"/* variable shapes */"); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); if (vsym->typ.dimset.ndims > 0) { nprintf(stmt,sizeof(stmt),"final int[] %s_dims = new int[RANK_%s];", jname(vsym), jname(vsym)); jlined(1,stmt); } } } } jflush(); /* create netCDF file, uses NC_CLOBBER mode */ jline(""); jlined(1,"/* enter define mode */"); if (!cmode_modifier) { cmode_string = "NC_CLOBBER"; } else if (cmode_modifier & NC_64BIT_OFFSET) { cmode_string = "NC_CLOBBER|NC_64BIT_OFFSET"; #ifdef USE_NETCDF4 } else if (cmode_modifier & NC_CLASSIC_MODEL) { cmode_string = "NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL"; } else if (cmode_modifier & NC_NETCDF4) { cmode_string = "NC_CLOBBER|NC_NETCDF4"; #endif } else { derror("unknown cmode modifier"); cmode_string = "NC_CLOBBER"; } nprintf(stmt,sizeof(stmt),"check_err(nc_create(\"%s\", %s, ncidp));", filename,cmode_string); jlined(1,stmt); jlined(1,"ncid = ncidp[0];"); jflush(); #ifdef USE_NETCDF4 /* Define the group structure */ /* ncid created above is also root group*/ if(!usingclassic) { nprintf(stmt,sizeof(stmt),"%s = ncid;",jgroupncid(rootgroup)); jlined(1,stmt); /* walking grpdefs list will do a preorder walk of all defined groups*/ for(igrp=0;igrpcontainer == NULL) PANIC("null container"); nprintf(stmt,sizeof(stmt), "check_err(nc_def_grp(%s, \"%s\", ncidp));", jgroupncid(gsym->container), gsym->name); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jgroupncid(gsym)); jlined(1,stmt); } jflush(); } #endif #ifdef USE_NETCDF4 /* Construct code to define types*/ if(ntyps > 0) { jline(""); for(ityp = 0; ityp < ntyps; ityp++) { Symbol* tsym = (Symbol*)listget(typdefs,ityp); if(tsym->subclass == NC_PRIM || tsym->subclass == NC_ARRAY) continue; /* no need to do these*/ genjjni_deftype(tsym); jline(""); } } jflush(); #endif /* define dimensions from info in dims array */ if (ndims > 0) { jline(""); jlined(1,"/* define dimensions */"); for(idim = 0; idim < ndims; idim++) { Symbol* dsym = (Symbol*)listget(dimdefs,idim); nprintf(stmt,sizeof(stmt), "check_err(nc_def_dim(%s, \"%s\", %s_len, ncidp));", jgroupncid(dsym->container), jescapifyname(dsym->name), jname(dsym)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jdimncid(dsym)); jlined(1,stmt); } } jflush(); /* define variables from info in vars array */ if (nvars > 0) { jline(""); jlined(1,"/* define variables */"); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; jline(""); if(dimset->ndims > 0) { for(idim = 0; idim < dimset->ndims; idim++) { Symbol* dsym = dimset->dimsyms[idim]; nprintf(stmt,sizeof(stmt), "%s_dims[%d] = %s;", jname(vsym), idim, jdimncid(dsym)); jlined(1,stmt); } } nprintf(stmt,sizeof(stmt), "check_err(nc_def_var(%s, \"%s\", %s, RANK_%s, %s, ncidp));", jgroupncid(vsym->container), jescapifyname(vsym->name), jtypencid(basetype), jname(vsym), (dimset->ndims == 0?"null":poolcat(jname(vsym),"_dims"))); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jvarncid(vsym)); jlined(1,stmt); #ifdef USE_NETCDF4 definespecialattributes(vsym); #endif /*USE_NETCDF4*/ } } jflush(); /* Define the global attributes*/ if(ngatts > 0) { jline(""); jlined(1,"/* assign global attributes */"); for(iatt = 0; iatt < ngatts; iatt++) { Symbol* gasym = (Symbol*)listget(gattdefs,iatt); genjjni_defineattribute(gasym); } jline(""); } jflush(); /* Define the variable specific attributes*/ if(natts > 0) { jline(""); jlined(1,"/* assign per-variable attributes */"); for(iatt = 0; iatt < natts; iatt++) { Symbol* asym = (Symbol*)listget(attdefs,iatt); genjjni_defineattribute(asym); } jline(""); } jflush(); if (nofill_flag) { jlined(1,"/* don't initialize variables with fill values */"); jlined(1,"check_err(nc_set_fill(%s, NC_NOFILL, 0));"); } jline(""); jlined(1,"/* leave define mode */"); nprintf(stmt,sizeof(stmt),"check_err(nc_enddef(%s));", jgroupncid(rootgroup)); jlined(1,stmt); jflush(); /* Load values into those variables with defined data */ if(nvars > 0) { jline(""); jlined(1,"/* assign variable data */"); for(ivar = 0; ivar < nvars; ivar++) { Symbol* vsym = (Symbol*)listget(vardefs,ivar); if(vsym->data != NULL) genjjni_definevardata(vsym); } jline(""); /* compute the max actual size of the unlimited dimension*/ if(usingclassic) computemaxunlimited(); } jflush(); } void cl_java_jni(void) { nprintf(stmt,sizeof(stmt),"check_err(nc_close(%s));", jgroupncid(rootgroup)); jlined(1,stmt); jline("}"); /* main */ jline("}"); /* class Main */ jflush(); } #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), "%scheck_err(nc_def_var_chunking(%s, %s, %s, ", indented(1), jgroupncid(vsym->container), jvarncid(vsym), (storage == NC_CONTIGUOUS?"NC_CONTIGUOUS":"NC_CHUNKED")); jpartial(stmt); if(special->nchunks == 0 || chunks == NULL) jpartial("new long[]{}"); else { nprintf(stmt,sizeof(stmt),"%s_chunksizes",jname(vsym)); jpartial(stmt); } jline("));"); } if(special->flags & _FLETCHER32_FLAG) { nprintf(stmt,sizeof(stmt), "check_err(nc_def_var_fletcher32(%s, %s, %d));", jgroupncid(vsym->container), jvarncid(vsym), special->_Fletcher32); jlined(1,stmt); } if(special->flags & (_DEFLATE_FLAG | _SHUFFLE_FLAG)) { nprintf(stmt,sizeof(stmt), "check_err(nc_def_var_deflate(%s, %s, %s, %d, %d));", jgroupncid(vsym->container), jvarncid(vsym), (special->_Shuffle == 1?"NC_SHUFFLE":"NC_NOSHUFFLE"), (special->_DeflateLevel >= 0?1:0), (special->_DeflateLevel >= 0?special->_DeflateLevel:0)); jlined(1,stmt); } if(special->flags & _ENDIAN_FLAG) { nprintf(stmt,sizeof(stmt), "check_err(nc_def_var_endian(%s, %s, %s));", jgroupncid(vsym->container), jvarncid(vsym), (special->_Endianness == NC_ENDIAN_LITTLE?"NC_ENDIAN_LITTLE" :"NC_ENDIAN_BIG") ); jlined(1,stmt); } if(special->flags & _NOFILL_FLAG) { nprintf(stmt,sizeof(stmt), "check_err(nc_def_var_fill(%s, %s, %s));", jgroupncid(vsym->container), jvarncid(vsym), (special->_Fill?"NC_FILL":"NC_NOFILL") ); jlined(1,stmt); } } #endif /*USE_NETCDF4*/ /* * Return java type name for netCDF type, given type code. */ const char* jtype(nc_type type) { 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 "long"; case NC_USHORT: return "long"; case NC_UINT: return "long"; case NC_INT64: return "long"; case NC_UINT64: return "long"; case NC_STRING: return "String"; case NC_ENUM: return "int"; case NC_OPAQUE: return "String"; default: PANIC1("ncctype: bad type code:%d",type); } return 0; } /* * Return a type name and dimensions for constant arrays * for netCDF type, given type code. */ const char* jarraytype(nc_type type) { switch (type) { case NC_CHAR: return "String"; 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 "long"; case NC_USHORT: return "long"; case NC_UINT: return "long"; case NC_INT64: return "long"; case NC_UINT64: return "long"; case NC_STRING: return "String"; case NC_ENUM: return "int"; case NC_OPAQUE: return "String"; default: PANIC1("ncctype: bad type code:%d",type); } return 0; } /* * Return netcdf interface type name for netCDF type suffix, given type code. */ const char* jstype(nc_type nctype) { switch (nctype) { case NC_CHAR: return "text"; case NC_BYTE: return "schar"; 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 "longlong"; case NC_UINT64: return "ulonglong"; case NC_STRING: return "string"; case NC_OPAQUE: return "opaque"; case NC_ENUM: return "enum"; default: derror("ncstype: bad type code: %d",nctype); return 0; } } /* Return the group name for the specified group*/ static const char* jgroupncid(Symbol* sym) { #ifdef USE_NETCDF4 if(usingclassic) { return "ncid"; } else { char* grptmp; const char* tmp1; if(sym == NULL) return jgroupncid(rootgroup); ASSERT(sym->objectclass == NC_GRP); tmp1 = jname(sym); grptmp = poolalloc(strlen(tmp1)+strlen("_grp")+1); strcpy(grptmp,tmp1); strcat(grptmp,"_grp"); return grptmp; } #else return "ncid"; #endif } /* Compute the name for a given type's id*/ /* Watch out: the result is a pool alloc*/ static const char* jtypencid(Symbol* tsym) { char* typtmp; const char* tmp1; if(tsym->subclass == NC_PRIM) return nctype(tsym->typ.typecode); tmp1 = jtypename(tsym); typtmp = poolalloc(strlen(tmp1)+strlen("_typ")+1); strcpy(typtmp,tmp1); strcat(typtmp,"_typ"); return typtmp; } /* Compute the name for a given var's id*/ /* Watch out: the result is a static*/ static const char* jvarncid(Symbol* vsym) { const char* tmp1; char* vartmp; tmp1 = jname(vsym); vartmp = poolalloc(strlen(tmp1)+strlen("_id")+1); strcpy(vartmp,tmp1); strcat(vartmp,"_id"); return vartmp; } /* Compute the name for a given dim's id*/ /* Watch out: the result is a static*/ static const char* jdimncid(Symbol* dsym) { const char* tmp1; char* dimtmp; tmp1 = jname(dsym); dimtmp = poolalloc(strlen(tmp1)+strlen("_dim")+1); strcpy(dimtmp,tmp1); strcat(dimtmp,"_dim"); return dimtmp; } /* Compute the C name for a given type*/ const char* jtypename(Symbol* tsym) { const char* name; ASSERT(tsym->objectclass == NC_TYPE); if(tsym->subclass == NC_PRIM) name = jtype(tsym->typ.typecode); else name = jname(tsym); return name; } #ifdef USE_NETCDF4 /* Only generate type info for enumerations */ static void definejtype(Symbol* tsym) { int i; int nconst; ASSERT(tsym->objectclass == NC_TYPE); if(tsym->subclass != NC_ENUM) return; /* start enum def */ nprintf(stmt,sizeof(stmt),"enum %s {",jtypename(tsym)); jline(stmt); /* define the constants */ nconst = listlength(tsym->subnodes); for(i=0;isubnodes,i); ASSERT(econst->subclass == NC_ECONST); nprintf(stmt,sizeof(stmt),"%s%s(%s)%s", indented(1), jtypename(econst), jconst(econst->typ.econst), (i == (nconst - 1)?";":",")); jlined(1,stmt); } /* add boilerplate */ nprintf(stmt,sizeof(stmt),"private final %s value;", jtypename(tsym->typ.basetype)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s(%s value) {this.value = value;}", jtypename(tsym),jtypename(tsym->typ.basetype)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"public %s value() {return this.value;}", jtypename(tsym->typ.basetype)); jlined(1,stmt); jline("}"); } /* Generate the code for defining a given type */ static void genjjni_deftype(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),"check_err(nc_def_opaque(%s, %lu, \"%s\", ncidp));", jgroupncid(tsym->container), tsym->typ.size, jescapifyname(tsym->name)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jtypencid(tsym)); jlined(1,stmt); break; case NC_ENUM: jlined(1,"{"); jlined(1,stmt); jlined(1,"long econst;"); nprintf(stmt,sizeof(stmt),"check_err(nc_def_enum(%s, %s, \"%s\", ncidp));", jgroupncid(tsym->container), nctype(tsym->typ.basetype->typ.typecode), jname(tsym)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jtypencid(tsym)); jlined(1,stmt); for(i=0;isubnodes);i++) { Symbol* econst = (Symbol*)listget(tsym->subnodes,i); ASSERT(econst->subclass == NC_ECONST); nprintf(stmt,sizeof(stmt),"econst = (long)%s.%s.value();", jname(tsym), jname(econst)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"check_err(nc_insert_enum(%s, %s, \"%s\", econst));", jgroupncid(tsym->container), jtypencid(tsym), jescapifyname(econst->name)); jlined(1,stmt); } jlined(1,"}"); break; case NC_VLEN: nprintf(stmt,sizeof(stmt),"stat = nc_def_vlen(%s, \"%s\", %s, ncidp);", jgroupncid(tsym->container), jescapifyname(tsym->name), jtypencid(tsym->typ.basetype)); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jtypencid(tsym)); jlined(1,stmt); break; case NC_COMPOUND: /* We cannot use sizeof(), so use the computed size */ nprintf(stmt,sizeof(stmt),"check_err(nc_def_compound(%s, %ld, \"%s\", ncidp));", jgroupncid(tsym->container), (unsigned long)tsym->typ.size, jtypename(tsym), tsym->name); jlined(1,stmt); nprintf(stmt,sizeof(stmt),"%s = ncidp[0];",jtypencid(tsym)); jlined(1,stmt); /* Generate the field dimension constants*/ jlined(1,"{"); for(i=0;isubnodes);i++) { int j; Symbol* efield = (Symbol*)listget(tsym->subnodes,i); ASSERT(efield->subclass == NC_FIELD); if(efield->typ.dimset.ndims == 0) continue; nprintf(stmt,sizeof(stmt),"final int %s_dims[] = new int[] {", jname(efield)); for(j=0;jtyp.dimset.ndims;j++) { char tmp[256]; Symbol* e = efield->typ.dimset.dimsyms[j]; ASSERT(e->dim.isconstant); snprintf(tmp,sizeof(tmp),"%u",e->dim.size); strcat(stmt,(j==0?"":", ")); strcat(stmt,tmp); } strcat(stmt,"};"); jlined(1,stmt); } for(i=0;isubnodes);i++) { Symbol* efield = (Symbol*)listget(tsym->subnodes,i); char tmp[1024]; ASSERT(efield->subclass == NC_FIELD); snprintf(tmp,sizeof(tmp),"%lu",efield->typ.offset); if(efield->typ.dimset.ndims > 0){ nprintf(stmt,sizeof(stmt),"check_err(nc_insert_array_compound(%s, %s, \"%s\", %s, %s, %d, %s_dims));", jgroupncid(tsym->container), jtypencid(tsym), jescapifyname(efield->name), tmp, jtypencid(efield->typ.basetype), efield->typ.dimset.ndims, jname(efield)); } else { nprintf(stmt,sizeof(stmt),"check_err(nc_insert_compound(%s, %s, \"%s\", %s, %s));", jgroupncid(tsym->container), jtypencid(tsym), jescapifyname(efield->name), tmp, jtypencid(efield->typ.basetype)); } jlined(1,stmt); } jlined(1,"}"); break; case NC_ARRAY: /* ignore: this will be handled by def_var*/ break; default: panic("genjjni_deftype: unexpected type subclass: %d",tsym->subclass); } } #endif static void genjjni_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"); nprintf(stmt,sizeof(stmt),"/* attribute: %s */",asym->name); jlined(1,stmt); code = bbNew(); genjjni_attrdata(asym,code); /* Handle primitives separately */ if(isprimplus(basetype->typ.typecode)) { if(basetype->typ.typecode != NC_CHAR) commify(code); genjjni_primattribute(asym, code, len); } else { /* User defined type */ #ifndef USE_NETCDF4 verror("Non-classic type: %s",nctypename(basetype->typ.typecode)); #else /* USE_NETCDF4 */ if(usingclassic && !isclassicprim(basetype->typ.typecode)) { verror("Non-classic type: %s",nctypename(basetype->typ.typecode)); return; } /* Dump the generation code */ jprint(code); nprintf(stmt,sizeof(stmt),"check_err(nc_put_att_memory(%s, %s, \"%s\", %s, %lu, memory));", jgroupncid(asym->container), (asym->att.var == NULL?"NC_GLOBAL" :jvarncid(asym->att.var)), jescapifyname(asym->name), jtypencid(basetype), len); jlined(1,stmt); #endif } bbFree(code); } static void genjjni_primattribute(Symbol* asym, Bytebuffer* code, unsigned long len) { Symbol* basetype = asym->typ.basetype; nc_type typecode = basetype->typ.typecode; /* Handle NC_CHAR specially */ if(typecode == NC_CHAR) { /* revise the length count */ len = bbLength(code); if(len == 0) {bbAppend(code,'\0'); len++;} jquotestring(code,'"'); } else { /* Convert to constant */ char* code2 = bbDup(code); bbClear(code); nprintf(stmt,sizeof(stmt),"new %s[]", jarraytype(typecode)); bbCat(code,stmt); bbCat(code,"{"); bbCat(code,code2); bbCat(code,"}"); efree(code2); } switch (typecode) { case NC_BYTE: case NC_SHORT: case NC_INT: case NC_FLOAT: case NC_DOUBLE: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_att_%s(%s, %s, \"%s\", %s, %lu, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(asym->container), (asym->att.var == NULL?"NC_GLOBAL" :jvarncid(asym->att.var)), jescapifyname(asym->name), jtypencid(basetype), len); jpartial(stmt); jprint(code); jline("));"); jflush(); break; case NC_CHAR: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_att_%s(%s, %s, \"%s\", %lu, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(asym->container), (asym->att.var == NULL?"NC_GLOBAL" :jvarncid(asym->att.var)), jescapifyname(asym->name), len); jpartial(stmt); jprint(code); jline("));"); jflush(); break; #ifdef USING_NETCDF4 /* !usingclassic only (except NC_STRING) */ case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_INT64: case NC_UINT64: case NC_STRING: if(usingclassic) { verror("Non-classic type: %s",njtypename(basetype->typ.typecode)); return; } nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_att_%s(%s, %s, \"%s\", %s, %lu, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(asym->container), (asym->att.var == NULL?"NC_GLOBAL" :jvarncid(asym->att.var)), jescapifyname(asym->name), jtypencid(basetype), len); jpartial(stmt); jprint(code); jline("));"); jflush(); break; #endif default: break; } } static void computemaxunlimited(void) { int i; unsigned long maxsize; Symbol* udim = rootgroup->grp.unlimiteddim; if(udim == NULL) return; /* there is no unlimited dimension*/ /* Look at each variable and see what*/ /* size it gives to the unlimited dim (if any)*/ maxsize = 0; for(i=0;ityp.dimset.ndims == 0) continue; /* rank == 0*/ dim = var->typ.dimset.dimsyms[0]; if(dim->dim.size != NC_UNLIMITED) continue; /* var does not use unlimited*/ if(var->typ.dimset.dimsyms[0]->dim.size > maxsize) maxsize = var->typ.dimset.dimsyms[0]->dim.size; } } /* Define the put_vara closure function for C data*/ /* Important assumptions: 1. The leftmost changed index controls the count set. 2. All indices to the right of #1 are assumed to be at there max values. */ static int jputvara(struct Putvar* closure, Odometer* odom, Bytebuffer* databuf) { int i; int stat = NC_NOERR; size_t startset[NC_MAX_VAR_DIMS]; size_t countset[NC_MAX_VAR_DIMS]; Symbol* vsym = closure->var; Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; Bytebuffer* code = closure->code; char dimstring[NC_MAX_VAR_DIMS*2+1]; size_t count; nc_type typecode = basetype->typ.typecode; memset((void*)startset,0,sizeof(startset)); memset((void*)countset,0,sizeof(countset)); #ifdef TRACE fprintf(stderr,"putvara: %s: ",vsym->name); fprintf(stderr,"odom = %s\n",odometerprint(odom)); fprintf(stderr,"initial startset = ["); for(i=0;irank;i++) fprintf(stderr,"%s%u",(i>0?", ":""),closure->startset[i]); fprintf(stderr,"]\n"); fflush(stderr); #endif /* Compute base on a change in the 0th dimension*/ for(i=1;irank;i++) { startset[i] = 0; countset[i] = odom->dims[i].datasize; } startset[0] = closure->startset[0]; countset[0] = odom->dims[0].index - startset[0]; #ifdef TRACE { fprintf(stderr,"startset = ["); for(i=0;irank;i++) fprintf(stderr,"%s%u",(i>0?", ":""),startset[i]); fprintf(stderr,"] "); fprintf(stderr,"countset = ["); for(i=0;irank;i++) fprintf(stderr,"%s%u",(i>0?", ":""),countset[i]); fprintf(stderr,"]\n"); fflush(stderr); } #endif /* generate constants for data*/ count = 1; dimstring[0] = '\0'; for(i=0;indims;i++) { count *= countset[i]; strcat(dimstring,"[]"); } /* define a block to avoid name clashes*/ nprintf(stmt,sizeof(stmt),"%s{\n",indented(1)); bbCat(code,stmt); /* generate constants for startset, countset*/ nprintf(stmt,sizeof(stmt),"%slong[] %s_startset = new long[] {", indented(1), jname(vsym)); bbCat(code,stmt); for(i=0;irank;i++) { nprintf(stmt,sizeof(stmt),"%s%lu",(i>0?", ":""),startset[i]); bbCat(code,stmt); } bbCat(code,"} ;\n"); nprintf(stmt,sizeof(stmt),"%slong[] %s_countset = new long[] {", indented(1), jname(vsym)); bbCat(code,stmt); for(i=0;irank;i++) { nprintf(stmt,sizeof(stmt),"%s%lu",(i>0?", ":""),countset[i]); bbCat(code,stmt); } bbCat(code,"} ;\n"); /* Handle primitives separately */ if(isprimplus(typecode)) { jputvaraprim(closure, odom,databuf,countset); } else { /* User defined type */ #ifndef USE_NETCDF4 verror("Non-classic type: %s",nctypename(basetype->typ.typecode)); #else /* USE_NETCDF4 */ if(usingclassic && !isclassicprim(basetype->typ.typecode)) { verror("Non-classic type: %s",nctypename(basetype->typ.typecode)); return NC_EINVAL; } /* Dump the generation code */ bbCat(code,bbContents(databuf)); nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_memory(%s, %s, %s_startset, %s_countset, memory));\n", indented(1), jgroupncid(vsym->container), jvarncid(vsym), jname(vsym), jname(vsym)); bbCat(code,stmt); #endif } /* end defined block*/ nprintf(stmt,sizeof(stmt),"%s}\n",indented(1)); bbCat(code,stmt); for(i=0;irank;i++) { closure->startset[i] = startset[i] + countset[i]; } bbClear(databuf); return stat; } static int jputvaraprim(struct Putvar* closure, Odometer* odom, Bytebuffer* databuf, size_t* countset) { int i; Symbol* vsym = closure->var; Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; Bytebuffer* code = closure->code; size_t len; nc_type typecode = basetype->typ.typecode; /* generate constants for data*/ len = 1; for(i=0;indims;i++) { len *= countset[i]; } /* Handle NC_CHAR specially */ if(typecode == NC_CHAR) { /* revise the length count */ len = bbLength(databuf); if(len == 0) {bbAppend(databuf,'\0'); len++;} jquotestring(databuf,'"'); } else { /* Convert to constant */ char* databuf2; commify(databuf); databuf2 = bbDup(databuf); bbClear(databuf); nprintf(stmt,sizeof(stmt),"new %s[]", jarraytype(typecode)); bbCat(databuf,stmt); bbCat(databuf,"{"); bbCat(databuf,databuf2); bbCat(databuf,"}"); efree(databuf2); } switch (typecode) { case NC_BYTE: case NC_SHORT: case NC_INT: case NC_FLOAT: case NC_DOUBLE: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_%s(%s, %s, %s_startset, %s_countset, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(vsym->container), jvarncid(vsym), jname(vsym), jname(vsym)); bbCat(code,stmt); bbCat(code,bbContents(databuf)); bbCat(code,"));\n"); break; case NC_CHAR: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_%s(%s, %s, %s_startset, %s_countset, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(vsym->container), jvarncid(vsym), jname(vsym), jname(vsym)); bbCat(code,stmt); bbCat(code,bbContents(databuf)); bbCat(code,"));\n"); break; #ifdef USE_NETCDF4 /* !usingclassic only (except NC_STRING) */ case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_INT64: case NC_UINT64: case NC_STRING: if(usingclassic) { verror("Non-classic type: %s",nctypename(typecode)); return NC_EINVAL; } nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_%s(%s, %s, %s_startset, %s_countset, ", indented(1), jstype(basetype->typ.typecode), jgroupncid(vsym->container), jvarncid(vsym), jname(vsym), jname(vsym)); bbCat(code,stmt); bbCat(code,bbContents(databuf)); bbCat(code,"));\n"); break; case NC_ENUM: case NC_OPAQUE: if(usingclassic) { verror("Non-classic type: %s",nctypename(typecode)); return NC_EINVAL; } /* We use some augmented vara procedures */ nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_%s(%s, %s, %s_startset, %s_countset, ", indented(1), (typecode == NC_ENUM?"enum":"opaque"), jgroupncid(vsym->container), jvarncid(vsym), jname(vsym), jname(vsym)); bbCat(code,stmt); bbCat(code,bbContents(databuf)); bbCat(code,"));\n"); break; #endif default: verror("Non-classic type: %s",nctypename(typecode)); } bbClear(databuf); return NC_NOERR; } static void genjjni_definevardata(Symbol* vsym) { Dimset* dimset = &vsym->typ.dimset; Symbol* basetype = vsym->typ.basetype; int rank = dimset->ndims; int isscalar = (dimset->ndims == 0); Bytebuffer* code; nc_type typecode = basetype->typ.typecode; if(vsym->data == NULL) return; code = bbNew(); /* Handle special cases first*/ if(isscalar) { genjjni_scalardata(vsym,code); if(isprimplus(typecode)) { genjjni_scalarprim(vsym,code); } else { nprintf(stmt,sizeof(stmt),"check_err(nc_put_var_memory(%s, %s, memory));", jgroupncid(vsym->container), jvarncid(vsym)); jlined(1,stmt); } } else { /* Non-scalar*/ Bytebuffer* databuf; /* build a closure*/ Putvar closure; closure.putvar = jputvara; closure.rank = rank; closure.code = code; closure.var = vsym; memset(closure.startset,0,sizeof(closure.startset)); /* Most complex case; use closure as needed*/ /* Use a separate data buffer to capture the data list*/ databuf = bbNew(); genjjni_arraydata(vsym,&closure,databuf); jprint(code); bbFree(databuf); } bbFree(code); } static void genjjni_scalarprim(Symbol* var, Bytebuffer* code) { Symbol* basetype = var->typ.basetype; nc_type typecode = basetype->typ.typecode; switch (typecode) { case NC_BYTE: case NC_SHORT: case NC_INT: case NC_FLOAT: case NC_DOUBLE: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_var_%s(%s, %s, (%s)", indented(1), ncstype(basetype->typ.typecode), jgroupncid(var->container), jvarncid(var), jtype(basetype->typ.typecode)); jpartial(stmt); jprint(code); jline("));"); jflush(); break; case NC_CHAR: nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_var_%s(%s, %s, ", indented(1), ncstype(basetype->typ.typecode), jgroupncid(var->container), jvarncid(var)); jpartial(stmt); jprint(code); jline("));"); jflush(); break; #ifdef USING_NETCDF4 /* !usingclassic only (except NC_STRING) */ case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_INT64: case NC_UINT64: case NC_STRING: if(usingclassic) { verror("Non-classic type: %s",njtypename(basetype->typ.typecode)); return; } nprintf(stmt,sizeof(stmt),"%scheck_err(nc_put_vara_%s(%s, %s, new long[]{0}, new long[]{1}, ", indented(1), ncstype(basetype->typ.typecode), jgroupncid(var->container), jvarncid(var)); jpartial(stmt); jprint(code); jline("));"); jflush(); break; #endif default: break; } } /* * Output a statement */ void jprint(Bytebuffer* buf) { bbAppendn(jcode,bbContents(buf),bbLength(buf)); } void jpartial(char* line) { bbCat(jcode,line); } void jline(char* line) { jpartial(line); bbCat(jcode,"\n"); } void jlined(int n, char* line) { bbCat(jcode,indented(n)); jline(line); } void jflush(void) { if(bbLength(jcode) > 0) { bbAppend(jcode,'\0'); fputs(bbContents(jcode),stdout); fflush(stdout); bbClear(jcode); } } /* Result is a pool string or a constant => do not free*/ char* jconst(Constant* ci) { char tmp[64]; tmp[0] = '\0'; switch (ci->nctype) { case NC_CHAR: { strcpy(tmp,"'"); escapifychar(ci->value.charv,tmp+1,'\''); strcat(tmp,"'"); } break; case NC_BYTE: snprintf(tmp,sizeof(tmp),"%hhd",ci->value.int8v); break; case NC_SHORT: snprintf(tmp,sizeof(tmp),"%hd",ci->value.int16v); break; case NC_INT: snprintf(tmp,sizeof(tmp),"%d",ci->value.int32v); break; case NC_FLOAT: snprintf(tmp,sizeof(tmp),"%.8g",ci->value.floatv); break; case NC_DOUBLE: snprintf(tmp,sizeof(tmp),"%.16g",ci->value.doublev); break; case NC_UBYTE: snprintf(tmp,sizeof(tmp),"%hhu",ci->value.uint8v); break; case NC_USHORT: snprintf(tmp,sizeof(tmp),"%hu",ci->value.uint16v); break; case NC_UINT: snprintf(tmp,sizeof(tmp),"%uL",ci->value.uint32v); /* upgrade to long */ break; case NC_INT64: snprintf(tmp,sizeof(tmp),"%lldL",ci->value.int64v); break; case NC_UINT64: { /* HACK to handle unsigned values */ long long l = (long)ci->value.uint64v; snprintf(tmp,sizeof(tmp),"%lldL",l); } break; case NC_ECONST: snprintf(tmp,sizeof(tmp),"%s",jname(ci->value.enumv)); break; case NC_STRING: { char* escaped = escapify(ci->value.stringv.stringv, '"',ci->value.stringv.len); char* result = poolalloc(1+2+strlen(escaped)); strcpy(result,"\""); strcat(result,escaped); strcat(result,"\""); return result; } break; case NC_OPAQUE: { char* bstring; char* p; int bslen; bslen=(4*ci->value.opaquev.len); bstring = poolalloc(bslen+2+1); strcpy(bstring,"\""); p = ci->value.opaquev.stringv; while(*p) { strlcat(bstring,"\\x",bslen+3); strlcat(bstring,p,bslen+3); p += 2; } strlcat(bstring,"\"",bslen+3); return bstring; } break; default: PANIC1("ncstype: bad type code: %d",ci->nctype); } return pooldup(tmp); /*except for NC_STRING and NC_OPAQUE*/ } void jquotestring(Bytebuffer* databuf, char quote) { char* escaped = jescapify(bbContents(databuf),'"',bbLength(databuf)); bbClear(databuf); bbAppend(databuf,quote); if(escaped != NULL) bbCat(databuf,escaped); bbAppend(databuf,quote); } /* Compute the name for a given symbol*/ /* Cache in symbol->lname*/ const char* jname(Symbol* sym) { if(sym->lname == NULL) { #ifdef USE_NETCDF4 if(sym->subclass == NC_FIELD || sym->subclass == NC_ECONST) { sym->lname = nulldup(jcodify(sym->name)); } else #endif if(sym->objectclass == NC_ATT && sym->att.var != NULL) { /* Attribute name must be prefixed with the cname of the*/ /* associated variable*/ char* lname; lname = (char*)ecalloc(strlen(sym->att.var->name) +strlen(sym->name) +1+1); lname[0] = '\0'; strcpy(lname,sym->att.var->name); strcat(lname,"_"); strcat(lname,sym->name); /* Now convert to java acceptable name */ sym->lname = nulldup(jcodify(lname)); } else { /* convert to language form*/ #ifdef USE_NETCDF4 sym->lname = nulldup(jcodify(jprefixed(sym->prefix,sym->name,"_"))); #else sym->lname = nulldup(jcodify(sym->name)); /* convert to usable form*/ #endif } } return sym->lname; } #ifdef USE_NETCDF4 /* Result is pool alloc'd*/ static char* jprefixed(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 pooldup(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 /*USE_NETCDF4*/ #endif /*ENABLE_JAVA*/