Resolve Lynton's vlen problems (partially) re: jira NCF-145

This commit is contained in:
Dennis Heimbigner 2012-02-14 00:25:32 +00:00
parent 513b094561
commit ea1af11655
45 changed files with 3491 additions and 4105 deletions

1
cf
View File

@ -100,6 +100,7 @@ FLAGS="$FLAGS --disable-pnetcdf"
#FLAGS="$FLAGS --with-libcf"
#FLAGS="$FLAGS --enable-benchmarks"
#FLAGS="$FLAGS --enable-extra-tests"
FLAGS="$FLAGS --enable-logging"
FLAGS="$FLAGS --disable-shared"
#FLAGS="$FLAGS --enable-shared"

View File

@ -5,12 +5,12 @@ PARMS="[log]"
#PARMS="${PARMS}[netcdf3]"
PARMS="${PARMS}[fetch=memory]"
PARMS="${PARMS}[cache]"
PARMS="${PARMS}[prefetch]"
#PARMS="${PARMS}[prefetch]"
#PARMS="${PARMS}[nocache]"
#PARMS="${PARMS}[noprefetch]"
PARMS="${PARMS}[show=fetch]"
F="file://${TOPDIR}/ncdap_test/testdata3/synth2"
F="[cache]file:///machine/netcdf/nc_test_7549/netcdf-4.2-snapshot2012021222/ncdap_test/testdata3/1998-6-avhrr.dat"
PROG="./ncd"
#PROG="../ncdump/ncdump"
@ -66,3 +66,4 @@ CON="ens,time,lat,lon,prmslmsl[0:1:0][0:1:64][0:1:10][0:1:10]"
F="http://motherlode.ucar.edu:8080/thredds/dodsC/station/metar/Surface_METAR_20111122_0000.nc"
CON="weather[0:10]"
fi

View File

@ -15,13 +15,10 @@ ref_tst_enum_data.cdl ref_tst_group_data.cdl \
ref_tst_nans.cdl ref_tst_opaque_data.cdl ref_tst_small.cdl \
ref_tst_solar_1.cdl ref_tst_solar_2.cdl ref_tst_special_atts.cdl \
ref_tst_string_data.cdl ref_tst_unicode.cdl ref_tst_utf8.cdl \
ref_tst_vlen_data.cdl ref_typescope.cdl sfc_pres_temp.cdl \
ref_typescope.cdl sfc_pres_temp.cdl \
simple_xy.cdl small.cdl small2.cdl test0.cdl tst_ncml.cdl \
bigf1.cdl bigf2.cdl bigf3.cdl bigr1.cdl bigr2.cdl bigr3.cdl \
n3time.cdl ref_tst_special_atts3.cdl ref_tst_unlim2.cdl ref_tst_chardata.cdl \
ref_solar.cdl unlimtest1.cdl unlimtest2.cdl
ref_solar.cdl unlimtest1.cdl unlimtest2.cdl \
ref_tst_opaque_data.cdl \
ref_tst_vlen_data.cdl ref_tst_vlen_data2.cdl

View File

@ -0,0 +1,129 @@
netcdf secondFile {
group: pfSystem {
types:
byte enum daysofWeekType { Monday = 3, Tuesday = 1, Wednesday = 7, Thursday= 9, Friday = 2 } ;
compound pfCoilType {
string name ;
string turns ;
string polarity ;
}; // pfCoilType
pfCoilType(*) vlen_t ;
compound pfCircuitType {
int id ;
string name ;
string description ;
vlen_t pfCoils ;
}; // pfCircuitType
int(*) vlen_int ;
vlen_int(*) vlen_int_vec
string(*) vlen_string ;
vlen_string(*) vlen_string_vec ;
compound singleCompoundType {
int scalarAtomicInt ;
int fixedLengthVectorAtomicInt(5) ;
string scalarString ;
string fixedLengthVectorString(5) ;
vlen_int vlenScalarInt ;
vlen_int vlenInt ;
vlen_int fixedLengthVectorVlenInt(3) ;
vlen_int_vec vlenVlenInt ;
vlen_string vlenScalarString ;
vlen_string vlenString ;
vlen_string fixedLengthVectorVlenString(3) ;
vlen_string_vec vlenVlenString ;
daysofWeekType daysOfWeek(10) ;
};
singleCompoundType(*) vlen_CompoundType;
dimensions:
pfCircuitCount = 10 ;
vlenDim = 3 ;
dayCount = 10 ;
variables:
daysofWeekType daysOfWeek(dayCount) ;
int scalarAtomicInt;
double scalarAtomicDouble;
int fixedLengthVectorAtomicInt(pfCircuitCount) ;
double fixedLengthVectorAtomicDouble(pfCircuitCount) ;
string scalarString ;
string fixedLengthVectorString(pfCircuitCount);
vlen_int vlenInt, vlenScalarInt, fixedLengthVectorVlenInt(vlenDim) ;
vlen_int_vec vlenVlenInt ;
vlen_string vlenString,vlenScalarString, fixedLengthVectorVlenString(vlenDim) ;
vlen_string_vec vlenVlenString ;
// singleCompoundType singleCompound ;
// vlen_CompoundType vlenCompound ;
data:
daysOfWeek = Monday, Thursday, Friday, Monday, Monday, Friday, Thursday, Thursday, Thursday, Tuesday ;
scalarAtomicInt = 10 ;
scalarAtomicDouble = 10.234 ;
fixedLengthVectorAtomicInt = -1,2,-3,4,-5,6,-7,8,-9,10;
fixedLengthVectorAtomicDouble = 1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1;
scalarString = "This is some data" ;
fixedLengthVectorString = "data1","data22","data333","data4444","data5","data6","data7","data8","data9","data10" ;
vlenInt = {9,2,4,6,8,0,-3};
vlenString = {"One", "Two", "Three", "Four", "Five", "Six", "Seven"};
vlenScalarInt = {3967};
vlenScalarString = {"Twenty"};
fixedLengthVectorVlenInt = {20,3,4,6}, {120,103,104}, {220,203};
vlenVlenInt = {{20,3,4,6}, {120,103,104}, {220,203}};
fixedLengthVectorVlenString = {"One","Two","Three","Four"},{"2One","2Two"},{"4One","4Two","4Three","4Four","4Five"};
vlenVlenString = {{"One","Two","Three","Four"},{"2One","2Two"},{"4One","4Two","4Three","4Four","4Five"}};
// singleCompound =
// {13,
// {1,2,3,4,5},
// "OHME",
// {"One","Two","Three","Four","Five"},
// {11},
// {21,22,23},
// {{111,112,113,114}, {121,122}, {131,132,133,134,135}},
// {{211,212,213,214}, {221,222}, {231,232,233,234,235},{241,242,243,244,245,246,247}},
// {"11s"},
// {"21s","22s","23s"},
// {{"111s","112s","113s"},{"121s","122s"},{"131s","132s","133s","134s","135s"}},
// {{"211s","212s","213s"},{"221s","222s"},{"231s","232s","233s","234s","235s"},{"241s","242s","243s","244s","245s","246s","247s"}},
// {Monday, Thursday, Friday, Monday, Monday, Friday, Thursday, Thursday, Thursday, Tuesday}
// };
// vlenCompound =
// {
// {13,
// {1,2,3,4,5},
// "OHME",
// {"One","Two","Three","Four","Five"},
// {11},
// {21,22,23},
// {{111,112,113,114}, {121,122}, {131,132,133,134,135}},
// {{211,212,213,214}, {221,222}, {231,232,233,234,235},{241,242,243,244,245,246,247}},
// {"11s"},
// {"21s","22s","23s"},
// {{"111s","112s","113s"},{"121s","122s"},{"131s","232s","133s","134s","135s"}},
// {{"211s","212s","213s"},{"221s","222s"},{"231s","232s","233s","234s","235s"},{"241s","242s","243s","244s","245s","246s","247s"}},
// {Monday, Thursday, Friday, Monday, Monday, Friday, Thursday, Thursday, Thursday, Tuesday}
// },
// {10,
// {10,20,30,40,50},
// "OHME2",
// {"One","Two","Three","Four","Five"},
// {110},
// {210,220,230},
// {{1110,1120,1130,1140}, {1210,1220}, {1310,1320,1330,1340,1350}},
// {{211,212,213,214}, {221,222}, {231,232,233,234,235},{241,242,243,244,245,246,247}},
// {"110s"},
// {"210s","220s","230s"},
// {{"1110s","1120s","1130s"},{"1210s","1220s"},{"1310s","1320s","1330s","1340s","1350s"}},
// {{"2110s","2120s","2130s"},{"2210s","2220s"},{"2310s","2320s","2330s","2340s","2350s"},{"2410s","2420s","2430s","2440s","2450s","2460s","2470s"}},
// {Monday, Thursday, Friday, Monday, Monday, Friday, Thursday, Thursday, Thursday, Tuesday}
// }
// };
//
} // group pfSystem
}

View File

@ -19,7 +19,10 @@ variables:
crop_harvest:long_name = "crop harvest attributes by\ncounty ID, year and practice" ;
data:
crop_harvest =
{111, 2011, 13,
{
111,
2011,
13,
{1, 2, 3},
{101, 102, 103},
{1.5, 2.5, 3.5},

View File

@ -15,10 +15,11 @@ ref_tst_enum_data.dmp ref_tst_group_data.dmp \
ref_tst_nans.dmp ref_tst_opaque_data.dmp ref_tst_small.dmp \
ref_tst_solar_1.dmp ref_tst_solar_2.dmp ref_tst_special_atts.dmp \
ref_tst_string_data.dmp ref_tst_unicode.dmp ref_tst_utf8.dmp \
ref_tst_vlen_data.dmp ref_typescope.dmp sfc_pres_temp.dmp \
ref_typescope.dmp sfc_pres_temp.dmp \
simple_xy.dmp small.dmp small2.dmp test0.dmp tst_ncml.dmp \
n3time.dmp ref_tst_special_atts3.dmp ref_tst_chardata.dmp ref_tst_unlim2.dmp \
ref_solar.dmp unlimtest1.dmp unlimtest2.dmp
ref_solar.dmp unlimtest1.dmp unlimtest2.dmp \
ref_tst_vlen_data.dmp ref_tst_vlen_data2.dmp
# These do not exist because they are not run as usual tests
# bigf1.dmp bigf2.dmp bigf3.dmp bigr1.dmp bigr2.dmp bigr3.dmp gfs1.dmp

View File

@ -0,0 +1,96 @@
netcdf ref_tst_vlen_data2 {
group: pfSystem {
types:
byte enum daysofWeekType {Monday = 3, Tuesday = 1, Wednesday = 7,
Thursday = 9, Friday = 2} ;
compound pfCoilType {
string name ;
string turns ;
string polarity ;
}; // pfCoilType
int(*) vlen_int ;
string(*) vlen_string ;
pfCoilType(*) vlen_t ;
compound pfCircuitType {
int id ;
string name ;
string description ;
vlen_t pfCoils ;
}; // pfCircuitType
vlen_int(*) vlen_int_vec ;
vlen_string(*) vlen_string_vec ;
compound singleCompoundType {
int scalarAtomicInt ;
int fixedLengthVectorAtomicInt(5) ;
string scalarString ;
string fixedLengthVectorString(5) ;
vlen_int vlenScalarInt ;
vlen_int vlenInt ;
vlen_int fixedLengthVectorVlenInt(3) ;
vlen_int_vec vlenVlenInt ;
vlen_string vlenScalarString ;
vlen_string vlenString ;
vlen_string fixedLengthVectorVlenString(3) ;
vlen_string_vec vlenVlenString ;
daysofWeekType daysOfWeek(10) ;
}; // singleCompoundType
singleCompoundType(*) vlen_CompoundType ;
dimensions:
pfCircuitCount = 10 ;
vlenDim = 3 ;
dayCount = 10 ;
variables:
daysofWeekType daysOfWeek(dayCount) ;
int scalarAtomicInt ;
double scalarAtomicDouble ;
int fixedLengthVectorAtomicInt(pfCircuitCount) ;
double fixedLengthVectorAtomicDouble(pfCircuitCount) ;
string scalarString ;
string fixedLengthVectorString(pfCircuitCount) ;
vlen_int vlenInt ;
vlen_int vlenScalarInt ;
vlen_int fixedLengthVectorVlenInt(vlenDim) ;
vlen_int_vec vlenVlenInt ;
vlen_string vlenString ;
vlen_string vlenScalarString ;
vlen_string fixedLengthVectorVlenString(vlenDim) ;
vlen_string_vec vlenVlenString ;
data:
daysOfWeek = Monday, Thursday, Friday, Monday, Monday, Friday, Thursday,
Thursday, Thursday, Tuesday ;
scalarAtomicInt = 10 ;
scalarAtomicDouble = 10.234 ;
fixedLengthVectorAtomicInt = -1, 2, -3, 4, -5, 6, -7, 8, -9, 10 ;
fixedLengthVectorAtomicDouble = 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8,
9.9, 10.1 ;
scalarString = "This is some data" ;
fixedLengthVectorString = "data1", "data22", "data333", "data4444",
"data5", "data6", "data7", "data8", "data9", "data10" ;
vlenInt = {9, 2, 4, 6, 8, 0, -3} ;
vlenScalarInt = {3967} ;
fixedLengthVectorVlenInt = {20, 3, 4, 6}, {120, 103, 104}, {220, 203} ;
vlenVlenInt = {{20, 3, 4, 6}, {120, 103, 104}, {220, 203}} ;
vlenString = {"One", "Two", "Three", "Four", "Five", "Six", "Seven"} ;
vlenScalarString = {"Twenty"} ;
fixedLengthVectorVlenString = {"One", "Two", "Three", "Four"},
{"2One", "2Two"}, {"4One", "4Two", "4Three", "4Four", "4Five"} ;
vlenVlenString =
{{"One", "Two", "Three", "Four"}, {"2One", "2Two"}, {"4One", "4Two", "4Three", "4Four", "4Five"}} ;
} // group pfSystem
}

View File

@ -69,14 +69,17 @@ ref_tst_comp2 \
ref_tst_comp3 \
ref_tst_group_data \
ref_tst_opaque_data \
ref_tst_vlen_data \
ref_tst_solar_1 \
ref_tst_solar_2 \
ref_tst_enum_data \
ref_tst_special_atts \
ref_tst_nans \
ref_solar \
unlimtest2"
unlimtest2 \
ref_tst_vlen_data \
ref_tst_vlen_data \
ref_tst_vlen_data2 \
"
SPECIALTESTS3="ref_tst_special_atts3"

View File

@ -9,7 +9,7 @@ LDADD = ${top_builddir}/liblib/libnetcdf.la
# Build ncgen from the listed sources.
bin_PROGRAMS = ncgen
ncgen_SOURCES=main.c cdata.c bindata.c genchar.c cvt.c data.c debug.c \
ncgen_SOURCES=generate.c main.c cdata.c bindata.c genchar.c cvt.c data.c debug.c \
escapes.c genc.c genbin.c generr.c genlib.c getfill.c odom.c offsets.c \
semantics.c ncgentab.c dump.c util.c bytebuffer.c list.c data.h \
debug.h generr.h genlib.h includes.h ncgen.h odom.h offsets.h dump.h \
@ -46,3 +46,37 @@ makeparser::
bison -pncg -t ncgen.y
rm -f ncgentab.c
mv ncgen.tab.c ncgentab.c
# Test c output
CTEST=test
btest::
./ncgen -k3 -lb ${CTEST}.cdl -o ${CTEST}.nc
../ncdump/ncdump ./${CTEST}.nc >${CTEST}.dmp
diff -wBb ${CTEST}.cdl ${CTEST}.dmp
ctest::
./ncgen -k3 -lc ${CTEST}.cdl >${CTEST}.c
CFLAGS=`../nc-config --cflags` \
LDFLAGS=`../nc-config --libs` \
gcc -o ${CTEST} -I../include ${CFLAGS} ${CTEST}.c ../liblib/.libs/libnetcdf.a ${LDFLAGS} -lm
./${CTEST}
../ncdump/ncdump ./${CTEST}.nc >${CTEST}.dmp
diff -wBb ${CTEST}.cdl ${CTEST}.dmp
ct::
CFLAGS=`../nc-config --cflags` \
LDFLAGS=`../nc-config --libs` \
gcc -o t -I../include ${CFLAGS} t.c ../liblib/.libs/libnetcdf.a ${LDFLAGS} -lm
./t
CLASSPATH=".:ncCore-4.2.jar"
jtest::
./ncgen -lj ${CTEST}.cdl >Main.java
javac -d . -classpath "${CLASSPATH}" Main.java
# java -cp ${CPATH} ./${CTEST}
# ../ncdump/ncdump ./${CTEST}.nc >${CTEST}.dmp
# diff -wBb ${CTEST}.cdl ${CTEST}.dmp

View File

@ -2,378 +2,154 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: bindata.c,v 1.3 2010/05/24 19:59:56 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/bindata.c,v 1.3 2010/05/24 19:59:56 dmh Exp $ */
#include "includes.h"
#include "nciter.h"
#ifdef ENABLE_BINARY
/**************************************************/
/* Code for generating binary data lists*/
/**************************************************/
/* For datalist constant rules: see the rules on the man page */
static int bin_uid = 0;
/* Forward */
static void bindata_primdata(Symbol*,Datasrc*,Bytebuffer*,Datalist*);
static void bindata_fieldarray(Symbol*, Datasrc*, Odometer*, Bytebuffer*, Datalist* fillsrc);
static void bindata_fieldarrayr(Symbol*,Datasrc*,Odometer*,int,Bytebuffer*,Datalist*);
/* Specialty wrappers for attributes and variables */
void
bindata_attrdata(Symbol* asym, Bytebuffer* memory)
static int
bin_charconstant(Generator* generator, Bytebuffer* buf, ...)
{
Datasrc* src;
int typecode = asym->typ.basetype->typ.typecode;
if(asym->data == NULL) return;
if(typecode == NC_CHAR) {
gen_charattr(asym,memory);
} else {
src = datalist2src(asym->data);
while(srcmore(src)) {
bindata_basetype(asym->typ.basetype,src,memory,NULL);
}
}
/* Just transfer charbuf to codebuf */
Bytebuffer* charbuf;
va_list ap;
vastart(ap,buf);
charbuf = va_arg(ap, Bytebuffer*);
va_end(ap);
bbNull(charbuf);
bbCatbuf(buf,charbuf);
return 1;
}
void
bindata_array(Symbol* vsym,
Bytebuffer* memory,
Datasrc* src,
Odometer* odom,
int index,
Datalist* fillsrc)
static int
bin_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
{
int i;
int rank = odom->rank;
int firstdim = (index == 0); /* first dimension*/
int lastdim = (index == (rank - 1)); /* last dimension*/
size_t count;
Symbol* basetype = vsym->typ.basetype;
int isunlimited = (odom->declsize[index] == 0);
int pushed = 0;
ASSERT(index >= 0 && index < rank);
/* Assume that src is already at the index of
everything read up to now */
count = odom->count[index];
/* Unpack the nested unlimited (unless first dimension)*/
if(!firstdim && isunlimited && issublist(src)) {
srcpush(src);
pushed = 1;
if(con->nctype != NC_ECONST) {
alignbuffer(con,buf);
}
if(lastdim) {
for(i=0;i<count;i++) {
bindata_basetype(basetype,src,memory,fillsrc);
}
} else {
/* walk count elements and generate recursively */
for(i=0;i<count;i++) {
bindata_array(vsym,memory,src,odom,index+1,fillsrc);
}
}
if(isunlimited && pushed) srcpop(src);
return;
}
/* Generate an instance of the basetype using datasrc */
void
bindata_basetype(Symbol* tsym, Datasrc* datasrc, Bytebuffer* memory, Datalist* fillsrc)
{
int usecmpd;
switch (tsym->subclass) {
case NC_ENUM:
case NC_OPAQUE:
case NC_PRIM:
if(issublist(datasrc)) {
semerror(srcline(datasrc),"Expected primitive found {..}");
}
bindata_primdata(tsym,datasrc,memory,fillsrc);
break;
case NC_COMPOUND: {
int i;
Constant* con;
if(!isfillvalue(datasrc) && !issublist(datasrc)) {/* fail on no compound*/
semerror(srcline(datasrc),"Compound data must be enclosed in {..}");
}
con = srcnext(datasrc);
if(con == NULL || con->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(tsym,fillsrc);
ASSERT(filler->length == 1);
con = &filler->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Compound data fill value is not enclosed in {..}");
}
}
srcpushlist(datasrc,con->value.compoundv); /* enter the sublist*/
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
bindata_basetype(field,datasrc,memory,NULL);
}
srcpop(datasrc);
} break;
case NC_VLEN: {
Constant* con;
nc_vlen_t ptr;
Bytebuffer* vlenmem;
int count;
int pushed = 0;
Datasrc* olddatasrc = NULL;
if(isfillvalue(datasrc)) {
con = srcnext(datasrc);
if(con == NULL || con->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(tsym,fillsrc);
ASSERT(filler->length == 1);
con = &filler->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Vlen data fill value is not enclosed in {..}");
} else {
olddatasrc = datasrc;
datasrc = const2src(con);
}
}
}
if(!issublist(datasrc)) {
semerror(srcline(datasrc),"Vlen data must be enclosed in {..}");
} else {
SRCPUSH(pushed,datasrc);
}
/* collect the nc_vlen_t instance*/
vlenmem = bbNew();
for(count=0;srcmore(datasrc);count++) {
bindata_basetype(tsym->typ.basetype,datasrc,vlenmem,NULL);
}
ptr.len = count;
ptr.p = bbDup(vlenmem);
bbFree(vlenmem);
bbAppendn(memory,(char*)&ptr,sizeof(ptr));
if(pushed) srcpop(datasrc);
if(olddatasrc) datasrc = olddatasrc;
switch (con->nctype) {
case NC_OPAQUE: {
unsigned char* bytes;
size_t len;
bytes=makebytestring(con->value.opaquev.stringv,&len);
bbAppendn(buf,(void*)bytes,len);
} break;
case NC_CHAR:
bbAppendn(buf,&con->value.charv,sizeof(con->value.charv));
break;
case NC_BYTE:
bbAppendn(buf,(void*)&con->value.int8v,sizeof(con->value.int8v));
break;
case NC_SHORT:
bbAppendn(buf,(void*)&con->value.int16v,sizeof(con->value.int16v));
break;
case NC_INT:
bbAppendn(buf,(void*)&con->value.int32v,sizeof(con->value.int32v));
break;
case NC_FLOAT:
bbAppendn(buf,(void*)&con->value.floatv,sizeof(con->value.floatv));
break;
case NC_DOUBLE:
bbAppendn(buf,(void*)&con->value.doublev,sizeof(con->value.doublev));
break;
case NC_UBYTE:
bbAppendn(buf,(void*)&con->value.uint8v,sizeof(con->value.uint8v));
break;
case NC_USHORT:
bbAppendn(buf,(void*)&con->value.uint16v,sizeof(con->value.uint16v));
break;
case NC_UINT:
bbAppendn(buf,(void*)&con->value.uint32v,sizeof(con->value.uint32v));
break;
case NC_INT64: {
union SI64 { char ch[8]; long long i64;} si64;
si64.i64 = con->value.int64v;
bbAppendn(buf,(void*)si64.ch,sizeof(si64.ch));
} break;
case NC_UINT64: {
union SU64 { char ch[8]; unsigned long long i64;} su64;
su64.i64 = con->value.uint64v;
bbAppendn(buf,(void*)su64.ch,sizeof(su64.ch));
} break;
case NC_STRING: {
char* ptr;
int len = (size_t)con->value.stringv.len;
ptr = (char*)malloc(len+1);
memcpy(ptr,con->value.stringv.stringv,len);
ptr[len] = '\0';
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
} break;
case NC_FIELD:
/* enclose in braces if and only if field is an array */
usecmpd = (issublist(datasrc) && tsym->typ.dimset.ndims > 0);
if(usecmpd) srcpush(datasrc);
if(tsym->typ.dimset.ndims > 0) {
Odometer* fullodom = newodometer(&tsym->typ.dimset,NULL,NULL);
bindata_fieldarray(tsym->typ.basetype,datasrc,fullodom,memory,fillsrc);
} else {
bindata_basetype(tsym->typ.basetype,datasrc,memory,NULL);
}
if(usecmpd) srcpop(datasrc);
break;
default: PANIC1("bindata_basetype: unexpected subclass %d",tsym->subclass);
default: PANIC1("bin_constant: unexpected type: %d",con->nctype);
}
return 1;
}
/* Used only for structure field arrays*/
static void
bindata_fieldarrayr(Symbol* basetype, Datasrc* src, Odometer* odom, int index,
Bytebuffer* memory, Datalist* fillsrc)
static int
bin_listbegin(Generator* generator, ListClass lc, size_t size, Bytebuffer* buf, int* uidp, ...)
{
int i;
int rank = odom->rank;
unsigned int size = odom->declsize[index];
int lastdim = (index == (rank - 1)); /* last dimension*/
ASSERT(size != 0);
for(i=0;i<size;i++) {
if(lastdim) {
bindata_basetype(basetype,src,memory,fillsrc);
} else { /* !lastdim*/
bindata_fieldarrayr(basetype,src,odom,index+1,memory,fillsrc);
}
}
if(uidp) *uidp = ++bin_uid;
return 1;
}
static void
bindata_fieldarray(Symbol* basetype, Datasrc* src, Odometer* odom,
Bytebuffer* memory, Datalist* fillsrc)
static int
bin_list(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
{
if(basetype->typ.typecode == NC_CHAR) {
/* Collect the char field in a separate buffer */
Bytebuffer* fieldbuf = bbNew();
gen_charfield(src,odom,fieldbuf);
bbAppendn(memory,bbContents(fieldbuf),bbLength(fieldbuf));
bbFree(fieldbuf);
} else {
bindata_fieldarrayr(basetype,src,odom,0,memory,fillsrc);
}
return 1;
}
static void
bindata_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* memory, Datalist* fillsrc)
static int
bin_listend(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
{
Constant* prim;
Constant target;
prim = srcnext(src);
if(prim == NULL) prim = &fillconstant;
ASSERT(prim->nctype != NC_COMPOUND);
if(prim->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(basetype,fillsrc);
ASSERT(filler->length == 1);
srcpushlist(src,filler);
bindata_primdata(basetype,src,memory,NULL);
srcpop(src);
goto done;
}
target.nctype = basetype->typ.typecode;
if(target.nctype != NC_ECONST) {
convert1(prim,&target);
alignbuffer(&target,memory);
}
switch (target.nctype) {
case NC_ECONST:
if(basetype->subclass != NC_ENUM) {
semerror(prim->lineno,"Conversion to enum not supported (yet)");
} else {
Datalist* econ = builddatalist(1);
srcpushlist(src,econ);
dlappend(econ,&prim->value.enumv->typ.econst);
bindata_primdata(prim->value.enumv->typ.basetype,src,memory,fillsrc);
srcpop(src);
}
break;
case NC_OPAQUE: {
unsigned char* bytes;
size_t len;
setprimlength(&target,basetype->typ.size*2);
bytes=makebytestring(target.value.opaquev.stringv,&len);
bbAppendn(memory,(void*)bytes,len);
} break;
case NC_CHAR:
bbAppendn(memory,&target.value.charv,sizeof(target.value.charv));
break;
case NC_BYTE:
bbAppendn(memory,(void*)&target.value.int8v,sizeof(target.value.int8v));
break;
case NC_SHORT:
bbAppendn(memory,(void*)&target.value.int16v,sizeof(target.value.int16v));
break;
case NC_INT:
bbAppendn(memory,(void*)&target.value.int32v,sizeof(target.value.int32v));
break;
case NC_FLOAT:
bbAppendn(memory,(void*)&target.value.floatv,sizeof(target.value.floatv));
break;
case NC_DOUBLE:
bbAppendn(memory,(void*)&target.value.doublev,sizeof(target.value.doublev));
break;
case NC_UBYTE:
bbAppendn(memory,(void*)&target.value.uint8v,sizeof(target.value.uint8v));
break;
case NC_USHORT:
bbAppendn(memory,(void*)&target.value.uint16v,sizeof(target.value.uint16v));
break;
case NC_UINT:
bbAppendn(memory,(void*)&target.value.uint32v,sizeof(target.value.uint32v));
break;
case NC_INT64: {
union SI64 { char ch[8]; long long i64;} si64;
si64.i64 = target.value.int64v;
bbAppendn(memory,(void*)si64.ch,sizeof(si64.ch));
} break;
case NC_UINT64: {
union SU64 { char ch[8]; unsigned long long i64;} su64;
su64.i64 = target.value.uint64v;
bbAppendn(memory,(void*)su64.ch,sizeof(su64.ch));
} break;
case NC_STRING: {
if(usingclassic) {
bbAppendn(memory,target.value.stringv.stringv,target.value.stringv.len);
} else if(target.nctype == NC_CHAR) {
bbAppendn(memory,target.value.stringv.stringv,target.value.stringv.len);
} else {
char* ptr;
int len = (size_t)target.value.stringv.len;
ptr = poolalloc(len+1); /* CAREFUL: this has short lifetime*/
memcpy(ptr,target.value.stringv.stringv,len);
ptr[len] = '\0';
bbAppendn(memory,(void*)&ptr,sizeof(ptr));
}
} break;
default: PANIC1("bindata_primdata: unexpected type: %d",target.nctype);
}
done:
return;
return 1;
}
#ifdef IGNORE
/*
This walk of the data lists collects
vlen sublists and constructs separate C constants
for each of them. The "id" of each list is then
recorded in the containing datalist.
*/
void
bindata_vlenconstants(List* vlenconstants)
static int
bin_vlendecl(Generator* generator, Bytebuffer* buf, Symbol* tsym, int uid, size_t count,...)
{
int i,nvlen;
Datasrc* vlensrc;
Bytebuffer* memory = bbNew();
/* Prepare a place to store vlen constants */
nvlen = listlength(vlenconstants);
if(nvlen == 0) return;
vlendata = (struct Vlendata*)emalloc(sizeof(struct Vlendata)*nvlen+1);
memset((void*)vlendata,0,sizeof(struct Vlendata)*nvlen+1);
for(i=0;i<nvlen;i++) {
Constant* cmpd = (Constant*)listget(vlenconstants,i);
int chartype;
Symbol* tsym = cmpd->value.compoundv->vlen.schema;
unsigned long uid = cmpd->value.compoundv->vlen.uid;
unsigned long count;
ASSERT(tsym != NULL);
chartype = (tsym->typ.basetype->typ.typecode == NC_CHAR);
vlensrc = datalist2src(cmpd->value.compoundv);
bbClear(memory);
count = 0;
if(chartype) {
/* Collect the char vlen in a separate buffer */
gen_charvlen(vlensrc,memory);
count = bbLength(memory);
} else {
while(srcmore(vlensrc)) {
bindata_basetype(tsym->typ.basetype,vlensrc,memory,NULL);
count++;
}
ASSERT(count == cmpd->value.compoundv->vlen.count);
}
vlendata[uid].data = bbDup(memory);
vlendata[uid].count = count;
}
bbFree(memory);
va_list ap;
Bytebuffer* vlenmem;
nc_vlen_t ptr;
vastart(ap,count);
vlenmem = va_arg(ap, Bytebuffer*);
va_end(ap);
ptr.len = count;
ptr.p = bbDup(vlenmem);
bbAppendn(buf,(char*)&ptr,sizeof(ptr));
return 1;
}
#endif /*IGNORE*/
static int
bin_vlenstring(Generator* generator, Bytebuffer* codebuf, int* uidp, size_t* sizep,...)
{
Bytebuffer* vlenmem;
nc_vlen_t ptr;
va_list ap;
if(uidp) *uidp = ++bin_uid;
vastart(ap,sizep);
vlenmem = va_arg(ap, Bytebuffer*);
va_end(ap);
ptr.len = bbLength(vlenmem);
ptr.p = bbDup(vlenmem);
bbAppendn(codebuf,(char*)&ptr,sizeof(ptr));
return 1;
}
/* Define the single static bin data generator */
static Generator bin_generator_singleton = {
NULL,
bin_charconstant,
bin_constant,
bin_listbegin,
bin_list,
bin_listend,
bin_vlendecl,
bin_vlenstring
};
Generator* bin_generator = &bin_generator_singleton;
#endif /*ENABLE_BINARY*/

View File

@ -26,9 +26,6 @@ EXTERNC int bbFill(Bytebuffer*, const char fill);
/* Produce a duplicate of the contents*/
EXTERNC char* bbDup(const Bytebuffer*);
/* pull a duplicate of the contents*/
EXTERNC char* bbDup(const Bytebuffer*);
/* Return the ith char; -1 if no such char */
EXTERNC int bbGet(Bytebuffer*,unsigned int);

View File

@ -2,424 +2,205 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: cdata.c,v 1.5 2010/05/24 19:59:56 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/cdata.c,v 1.5 2010/05/24 19:59:56 dmh Exp $ */
#include "includes.h"
#include "nciter.h"
#ifdef ENABLE_C
#include <math.h>
#include <math.h>
static int c_uid = 0;
/**************************************************/
/* Code for generating C language data lists*/
/**************************************************/
/* For datalist constant rules: see the rules on the man page */
/* Forward*/
static void cdata_primdata(Symbol*, Datasrc*, Bytebuffer*, Datalist*);
static void cdata_fieldarray(Symbol*, Datasrc*, Odometer*, int, Bytebuffer*, Datalist* fillsrc);
/* vlen uid generator */
static int uid = 0;
/* Specialty wrappers for cdata_data */
void
cdata_attrdata(Symbol* asym, Bytebuffer* codebuf)
static int
c_charconstant(Generator* generator, Bytebuffer* codebuf, ...)
{
Datasrc* src;
int typecode = asym->typ.basetype->typ.typecode;
if(asym->data == NULL) return;
if(typecode == NC_CHAR) {
gen_charattr(asym,codebuf);
} else {
src = datalist2src(asym->data);
while(srcmore(src)) {
bbAppend(codebuf,' ');
cdata_basetype(asym->typ.basetype,src,codebuf,NULL);
}
}
/* Escapes and quoting will be handled in genc_write */
/* Just transfer charbuf to codebuf */
Bytebuffer* charbuf;
va_list ap;
vastart(ap,codebuf);
charbuf = va_arg(ap, Bytebuffer*);
va_end(ap);
bbNull(charbuf);
bbCatbuf(codebuf,charbuf);
return 1;
}
void
cdata_array(Symbol* vsym,
Bytebuffer* codebuf,
Datasrc* src,
Odometer* odom,
int index,
Datalist* fillsrc)
{
int i;
int rank = odom->rank;
int pushed = 0;
size_t count;
Symbol* basetype = vsym->typ.basetype;
int lastdim = (index == (rank - 1)); /* last dimension*/
int firstdim = (index == 0); /* first dimension*/
int isunlimited = (odom->declsize[index] == 0);
ASSERT(index >= 0 && index < rank);
count = odom->count[index];
if(!firstdim && isunlimited && issublist(src)) {
srcpush(src);
pushed = 1;
}
if(lastdim) {
for(i=0;i<count;i++) {
cdata_basetype(basetype,src,codebuf,fillsrc);
}
} else {
/* now walk count elements and generate recursively */
for(i=0;i<count;i++) {
cdata_array(vsym,codebuf,src,odom,index+1,fillsrc);
}
}
if(isunlimited && pushed) srcpop(src);
return;
}
/* Generate an instance of the basetype using datasrc */
void
cdata_basetype(Symbol* tsym, Datasrc* datasrc, Bytebuffer* codebuf, Datalist* fillsrc)
{
int usecmpd;
switch (tsym->subclass) {
case NC_ENUM:
case NC_OPAQUE:
case NC_PRIM:
if(issublist(datasrc)) {
semerror(srcline(datasrc),"Expected primitive found {..}");
}
bbAppend(codebuf,' ');
cdata_primdata(tsym,datasrc,codebuf,fillsrc);
break;
case NC_COMPOUND: {
int i;
Constant* con;
if(!isfillvalue(datasrc) && !issublist(datasrc)) {/* fail on no compound*/
semerror(srcline(datasrc),"Compound data must be enclosed in {..}");
}
con = srcnext(datasrc);
if(con == NULL || con->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(tsym,fillsrc);
ASSERT(filler->length == 1);
con = &filler->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Compound data fill value is not enclosed in {..}");
}
}
srcpushlist(datasrc,con->value.compoundv); /* enter the sublist*/
bbAppend(codebuf,'{');
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
bbAppend(codebuf,' ');
cdata_basetype(field,datasrc,codebuf,NULL);
}
bbAppend(codebuf,'}');
srcpop(datasrc);
} break;
case NC_VLEN: {
Constant* con;
#ifdef NOTUSED
nc_vlen_t ptr;
#endif
Bytebuffer* vlenmem;
int count;
int pushed = 0;
Datasrc* olddatasrc = NULL;
if(isfillvalue(datasrc)) {
con = srcnext(datasrc);
if(con == NULL || con->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(tsym,fillsrc);
ASSERT(filler->length == 1);
con = &filler->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Vlen data fill value is not enclosed in {..}");
} else {
olddatasrc = datasrc;
datasrc = const2src(con);
}
}
}
if(!issublist(datasrc)) {
semerror(srcline(datasrc),"Vlen data must be enclosed in {..}");
} else {
SRCPUSH(pushed,datasrc);
}
/* generate the nc_vlen_t instance*/
vlenmem = bbNew();
for(count=0;srcmore(datasrc);count++) {
cdata_basetype(tsym->typ.basetype,datasrc,vlenmem,NULL);
}
/* generate the nc_vlen_t instance*/
bbprintf0(stmt,"{%u (void*)vlen_%u}",count,++uid);
bbCatbuf(codebuf,stmt);
#ifdef NOTUSED
ptr.len = count;
ptr.p = bbDup(vlenmem);
#endif
bbFree(vlenmem);
if(pushed) srcpop(datasrc);
if(olddatasrc) datasrc = olddatasrc;
} break;
case NC_FIELD:
/* enclose in braces if and only if field is an array */
usecmpd = (issublist(datasrc) && tsym->typ.dimset.ndims > 0);
if(usecmpd) srcpush(datasrc);
if(tsym->typ.dimset.ndims > 0) {
Odometer* fullodom = newodometer(&tsym->typ.dimset,NULL,NULL);
cdata_fieldarray(tsym->typ.basetype,datasrc,fullodom,0,codebuf,fillsrc);
odometerfree(fullodom);
} else {
cdata_basetype(tsym->typ.basetype,datasrc,codebuf,NULL);
}
if(usecmpd) srcpop(datasrc);
break;
default: PANIC1("cdata_basetype: unexpected subclass %d",tsym->subclass);
}
}
/* Used only for structure field arrays*/
static void
cdata_fieldarray(Symbol* basetype, Datasrc* src, Odometer* odom, int index,
Bytebuffer* codebuf, Datalist* fillsrc)
{
int i;
int rank = odom->rank;
unsigned int size = odom->declsize[index];
int lastdim = (index == (rank - 1)); /* last dimension*/
int chartype = (basetype->typ.typecode == NC_CHAR);
if(chartype) {
/* Collect the char field in a separate buffer */
Bytebuffer* fieldbuf = bbNew();
gen_charfield(src,odom,fieldbuf);
/* Add to the existing data buf as a single constant */
cquotestring(fieldbuf);
bbCat(codebuf," ");
bbCatbuf(codebuf,fieldbuf);
bbFree(fieldbuf);
} else {
ASSERT(size != 0);
for(i=0;i<size;i++) {
if(lastdim) {
bbAppend(codebuf,' ');
cdata_basetype(basetype,src,codebuf,NULL);
} else { /* !lastdim*/
cdata_fieldarray(basetype,src,odom,index+1,codebuf,fillsrc);
}
}
}
}
static void
cdata_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* codebuf, Datalist* fillsrc)
{
Constant* prim;
Constant target;
prim = srcnext(src);
if(prim == NULL) prim = &fillconstant;
ASSERT(prim->nctype != NC_COMPOUND);
if(prim->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(basetype,fillsrc);
ASSERT(filler->length == 1);
srcpushlist(src,filler);
bbAppend(codebuf,' ');
cdata_primdata(basetype,src,codebuf,NULL);
srcpop(src);
goto done;
}
target.nctype = basetype->typ.typecode;
if(target.nctype != NC_ECONST) {
convert1(prim,&target);
}
switch (target.nctype) {
case NC_ECONST:
if(basetype->subclass != NC_ENUM) {
semerror(prim->lineno,"Conversion to enum not supported (yet)");
} else {
Datalist* econ = builddatalist(1);
Symbol* enumv = prim->value.enumv;
srcpushlist(src,econ);
dlappend(econ,&enumv->typ.econst);
cdata_primdata(enumv->typ.basetype,src,codebuf,fillsrc);
srcpop(src);
} break;
case NC_OPAQUE: {
setprimlength(&target,basetype->typ.size*2);
} break;
default: break;
}
bbCat(codebuf,cdata_const(&target));
done:
return;
}
/*
This walk of the data lists collects
vlen sublists and constructs separate C constants
for each of them. The "id" of each list is then
recorded in the containing datalist.
*/
void
cdata_vlenconstants(List* vlenconstants, Bytebuffer* codebuf)
{
int i,nvlen;
Datasrc* vlensrc;
Bytebuffer* tmp = bbNew();
nvlen = listlength(vlenconstants);
for(i=0;i<nvlen;i++) {
Constant* cmpd = (Constant*)listget(vlenconstants,i);
int chartype;
Symbol* tsym = cmpd->value.compoundv->vlen.schema;
ASSERT(tsym != NULL);
chartype = (tsym->typ.basetype->typ.typecode == NC_CHAR);
bbprintf0(tmp,"static const %s vlen_%u[] = ",
ctypename(tsym->typ.basetype),
cmpd->value.compoundv->vlen.uid);
bbCatbuf(codebuf,tmp);
vlensrc = datalist2src(cmpd->value.compoundv);
bbAppend(codebuf,'{');
if(chartype) {
/* Collect the char vlen in a separate buffer */
Bytebuffer* vlenbuf = bbNew();
gen_charvlen(vlensrc,vlenbuf);
/* Add to the existing data buf as a single constant */
cquotestring(vlenbuf);
bbCatbuf(codebuf,vlenbuf);
bbFree(vlenbuf);
} else {
size_t count = 0;
while(srcmore(vlensrc)) {
if(count > 0) bbCat(codebuf,", ");
cdata_basetype(tsym->typ.basetype,vlensrc,codebuf,NULL);
count++;
}
ASSERT(count == cmpd->value.compoundv->vlen.count);
}
bbCat(codebuf,"} ;\n");
}
bbFree(tmp);
}
/* Result is a pool string or a constant => do not free*/
char*
cdata_const(Constant* ci)
static int
c_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
{
Bytebuffer* codetmp = bbNew();
char* result;
char* special = NULL;
switch (ci->nctype) {
case NC_CHAR:
{
char tmp[64];
tmp[0] = '\0';
escapifychar(ci->value.charv,tmp,'\'');
bbCat(codetmp,"'");
bbCat(codetmp,tmp);
bbCat(codetmp,"'");
}
break;
switch (con->nctype) {
case NC_BYTE:
bbprintf(codetmp,"%hhd",ci->value.int8v);
bbprintf(codetmp,"%hhd",con->value.int8v);
break;
case NC_SHORT:
bbprintf(codetmp,"%hd",ci->value.int16v);
bbprintf(codetmp,"%hd",con->value.int16v);
break;
case NC_INT:
bbprintf(codetmp,"%d",ci->value.int32v);
bbprintf(codetmp,"%d",con->value.int32v);
break;
case NC_FLOAT:
/* Special case for nanf */
if(isnan(ci->value.floatv))
if(isnan(con->value.floatv))
bbprintf(codetmp,"nanf");
else
bbprintf(codetmp,"%f",ci->value.floatv);
bbprintf(codetmp,"%f",con->value.floatv);
break;
case NC_DOUBLE:
/* Special case for nanf */
if(isnan(ci->value.doublev))
/* Special case for nan */
if(isnan(con->value.doublev))
bbprintf(codetmp,"nan");
else
bbprintf(codetmp,"%lf",ci->value.doublev);
bbprintf(codetmp,"%lf",con->value.doublev);
break;
case NC_UBYTE:
bbprintf(codetmp,"%hhu",ci->value.uint8v);
bbprintf(codetmp,"%hhu",con->value.uint8v);
break;
case NC_USHORT:
bbprintf(codetmp,"%hu",ci->value.uint16v);
bbprintf(codetmp,"%hu",con->value.uint16v);
break;
case NC_UINT:
bbprintf(codetmp,"%uU",ci->value.uint32v);
bbprintf(codetmp,"%uU",con->value.uint32v);
break;
case NC_INT64:
bbprintf(codetmp,"%lldLL",ci->value.int64v);
bbprintf(codetmp,"%lldLL",con->value.int64v);
break;
case NC_UINT64:
bbprintf(codetmp,"%lluLLU",ci->value.uint64v);
bbprintf(codetmp,"%lluLLU",con->value.uint64v);
break;
case NC_ECONST:
bbprintf(codetmp,"%s",cname(ci->value.enumv));
break;
case NC_STRING:
{ /* handle separately */
char* escaped = escapify(ci->value.stringv.stringv,
'"',ci->value.stringv.len);
result = poolalloc(1+2+strlen(escaped));
strcpy(result,"\"");
strcat(result,escaped);
strcat(result,"\"");
goto done;
}
bbprintf(codetmp,"%s",cname(con->value.enumv));
break;
case NC_STRING: { /* handle separately */
char* escaped = escapify(con->value.stringv.stringv,
'"',con->value.stringv.len);
special = poolalloc(1+2+strlen(escaped));
strcpy(special,"\"");
strcat(special,escaped);
strcat(special,"\"");
} break;
case NC_OPAQUE: {
char* p;
int bslen;
bslen=(4*ci->value.opaquev.len);
result = poolalloc(bslen+2+1);
strcpy(result,"\"");
p = ci->value.opaquev.stringv;
bslen=(4*con->value.opaquev.len);
special = poolalloc(bslen+2+1);
strcpy(special,"\"");
p = con->value.opaquev.stringv;
while(*p) {
strcat(result,"\\x");
strncat(result,p,2);
strcat(special,"\\x");
strncat(special,p,2);
p += 2;
}
strcat(result,"\"");
goto done;
strcat(special,"\"");
} break;
default: PANIC1("ncstype: bad type code: %d",ci->nctype);
default: PANIC1("ncstype: bad type code: %d",con->nctype);
}
result = pooldup(bbContents(codetmp)); /*except for NC_STRING and NC_OPAQUE*/
if(special == NULL)
bbCatbuf(buf,codetmp);
else
bbCat(buf,special);
bbFree(codetmp);
done:
return result;
return 1;
}
static int
c_listbegin(Generator* generator, ListClass lc, size_t size, Bytebuffer* codebuf, int* uidp, ...)
{
if(uidp) *uidp = ++c_uid;
switch (lc) {
case LISTVLEN:
case LISTATTR:
case LISTDATA:
break;
case LISTFIELDARRAY:
case LISTCOMPOUND:
bbAppend(codebuf,'{');
break;
}
return 1;
}
static int
c_list(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* codebuf, ...)
{
switch (lc) {
case LISTVLEN:
case LISTATTR:
if(count > 0) bbCat(codebuf,", ");
break;
case LISTDATA:
case LISTCOMPOUND:
case LISTFIELDARRAY:
bbAppend(codebuf,' ');
break;
}
return 1;
}
static int
c_listend(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
{
switch (lc) {
case LISTCOMPOUND:
case LISTFIELDARRAY:
bbAppend(buf,'}');
break;
case LISTDATA:
case LISTVLEN:
case LISTATTR:
break;
}
return 1;
}
static int
c_vlendecl(Generator* generator, Bytebuffer* codebuf, Symbol* tsym, int uid, size_t count, ...)
{
/* Build a bytebuffer to capture the vlen decl */
List* declstack = (List*)generator->state;
Bytebuffer* decl = bbNew();
Bytebuffer* vlenbuf;
va_list ap;
vastart(ap,count);
vlenbuf = va_arg(ap, Bytebuffer*);
va_end(ap);
bbprintf0(decl,"static const %s vlen_%u[] = {",
ctypename(tsym->typ.basetype),
uid);
commify(vlenbuf);
bbCatbuf(decl,vlenbuf);
bbCat(decl,"} ;");
listpush(declstack,(elem_t)decl);
/* Now generate the reference to buffer */
bbprintf(codebuf,"{%u,(void*)vlen_%u}",count,uid);
return 1;
}
static int
c_vlenstring(Generator* generator, Bytebuffer* vlenmem, int* uidp, size_t* countp,...)
{
if(uidp) *uidp = ++c_uid;
if(countp) *countp = bbLength(vlenmem);
return 1;
}
/* Define the single static bin data generator */
static Generator c_generator_singleton = {
NULL,
c_charconstant,
c_constant,
c_listbegin,
c_list,
c_listend,
c_vlendecl,
c_vlenstring
};
Generator* c_generator = &c_generator_singleton;
#endif /*ENABLE_C*/

View File

@ -18,6 +18,8 @@ convert1(Constant* src, Constant* dst)
unsigned char* bytes = NULL;
size_t bytelen;
dst->lineno = src->lineno;
/* Need to translate all possible sources to all possible sinks.*/
/* Rather than have a nested switch, combine the src and target into*/
/* a single value so we can do a single n*n-way switch*/

View File

@ -221,21 +221,6 @@ srcsplice(Datasrc* ds, Datalist* list)
ds->spliced = 1;
}
void
srcmove(Datasrc* ds, size_t delta)
{
srcmoveto(ds,ds->index+delta);
}
void
srcmoveto(Datasrc* ds, size_t pos)
{
if(pos >= ds->length)
ds->index = ds->length;
else
ds->index = pos;
}
void
srcsetfill(Datasrc* ds, Datalist* list)
{
@ -262,13 +247,14 @@ bbFree(buf);
void
report0(char* lead, Datasrc* src, int index)
{
if(debug == 0) return;
#ifdef IGNORE
fprintf(stderr,"%s src ",lead);
if(index >=0 ) fprintf(stderr,"(%d)",index);
fprintf(stderr,":: ");
dumpdatasrc(src);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
#endif
@ -360,7 +346,8 @@ datalistline(Datalist* ds)
and insert commas as needed; ideally, this
operation should be idempotent so that
the caller need not worry about it having already
been applied.
been applied. Also, handle situation where there may be missing
matching right braces.
*/
static char* commifyr(char* p, Bytebuffer* buf);
@ -380,6 +367,9 @@ commify(Bytebuffer* buf)
efree(list);
}
/* Requires that the string be balanced
WRT to braces
*/
static char*
commifyr(char* p, Bytebuffer* buf)
{
@ -388,7 +378,9 @@ commifyr(char* p, Bytebuffer* buf)
while((c=*p++)) {
if(c == ' ') continue;
if(c == ',') continue;
else if(c == '}') break;
else if(c == '}') {
break;
}
if(comma) bbCat(buf,", "); else comma=1;
if(c == '{') {
bbAppend(buf,'{');
@ -473,6 +465,7 @@ void
codedump(Bytebuffer* buf)
{
bbCatbuf(codebuffer,buf);
bbClear(buf);
}
void
@ -591,10 +584,10 @@ retry: switch ((c=*p++)) {
break;
case 'f':
if(lcount > 0) {
snprintf(tmp,sizeof(tmp),"%.16g",
snprintf(tmp,sizeof(tmp),"((double)%.16g)",
(double)va_arg(argv,double));
} else {
snprintf(tmp,sizeof(tmp),"%.8g",
snprintf(tmp,sizeof(tmp),"((float)%.8g)",
(double)va_arg(argv,double));
}
bbCat(buf,tmp);
@ -658,3 +651,21 @@ emptystringconst(int lineno, Constant* c)
c->value.stringv.stringv = NULL;
return c;
}
#define INDENTMAX 256
static char* dent = NULL;
char*
indented(int n)
{
char* indentation;
if(dent == NULL) {
dent = (char*)emalloc(INDENTMAX+1);
memset((void*)dent,' ',INDENTMAX);
dent[INDENTMAX] = '\0';
}
if(n*4 >= INDENTMAX) n = INDENTMAX/4;
indentation = dent+(INDENTMAX - 4*n);
return indentation;
}

View File

@ -2,15 +2,25 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: data.h,v 1.5 2010/05/24 19:59:56 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/data.h,v 1.5 2010/05/24 19:59:56 dmh Exp $ */
#ifndef DATA_H
#define DATA_H 1
#ifndef NO_STDARG
# include <stdarg.h>
#else
# include <varargs.h>
#endif
/* nmemonic*/
#define TOPLEVEL 1
/* Forward types */
struct Datalist;
struct Symbol;
struct Dimset;
typedef struct Generator Generator;
/* any one possible value*/
typedef union Constvalue {
struct Datalist* compoundv; /* NC_COMPOUND*/
@ -65,7 +75,6 @@ typedef struct Datalist {
location of current read point in the Datalist sequence
In effect, we are parsing the data sequence.
Push and pop of data sources is supported (see srcpush() below).*/
typedef struct Datasrc {
Constant* data; /* duplicate pointer; so do not free.*/
int index;
@ -81,71 +90,13 @@ struct Vlendata {
};
extern struct Vlendata* vlendata;
/* Convenience*/
#define SRCPUSH(iscmpd,src) {if(((iscmpd)=issublist(src))) {srcpush(src);}}
#define SRCPOP(iscmpd,src) {if((iscmpd)) {srcpop(src);}}
/* from: data.c */
int issublist(Datasrc* src);
int isstring(Datasrc* src);
int isfillvalue(Datasrc* src);
int istype(Datasrc* src, nc_type);
int isstringable(nc_type nctype);
#ifdef ENABLE_BINARY
/* from: cdfdata.c */
void bindata_array(struct Symbol*,Bytebuffer*,Datasrc*,Odometer*,int,Datalist*);
void bindata_attrdata(struct Symbol* asym, Bytebuffer*);
void bindata_vardata(struct Symbol* vsym, Bytebuffer*);
void bindata_basetype(struct Symbol*,struct Datasrc*,Bytebuffer*,struct Datalist*);
#endif
#ifdef ENABLE_C
/* from: cdata.c */
void cdata_attrdata(struct Symbol* asym, Bytebuffer*);
void cdata_array(struct Symbol*,Bytebuffer*,Datasrc*,Odometer*,int,Datalist*);
void cdata_basetype(struct Symbol*,struct Datasrc*,Bytebuffer*,struct Datalist*);
void cdata_vlenconstants(List*,Bytebuffer*);
char* cdata_const(Constant*);
#endif
#ifdef ENABLE_F77
/* from: f77data.c */
void f77data_attrdata(struct Symbol* asym, Bytebuffer*);
void f77data_array(struct Symbol*,Bytebuffer*,Datasrc*,Odometer*,int,Datalist*);
void f77data_basetype(struct Symbol*,struct Datasrc*,Bytebuffer*,struct Datalist*);
char* f77data_const(Constant* ci);
void f77quotestring(Bytebuffer* databuf);
#endif
#ifdef ENABLE_CML
/* from: cmldata.c */
void gencml_attrdata(struct Symbol* asym, Bytebuffer*);
void gencml_scalardata(struct Symbol* vsym, Bytebuffer*);
void gencml_arraydata(struct Symbol* vsym, Bytebuffer*);
void gencml_vlenconstants(List*, Bytebuffer*);
void gencml_fillvalue(struct Symbol*, Datalist*, Datasrc*, Bytebuffer*);
void xquotestring(Bytebuffer* databuf);
char* xconst(Constant* ci);
#endif
#ifdef ENABLE_JAVA
/* from: jdata.c */
void jdata_array(struct Symbol*,Bytebuffer*,Datasrc*,Odometer*,int,Datalist*);
void jdata_basetype(struct Symbol*,struct Datasrc*,Bytebuffer*,struct Datalist*);
char* jdata_const(Constant* ci);
void jquotestring(Bytebuffer* databuf, char);
#endif
/* from: data.c */
Constant gen_string(unsigned long, Datasrc*);
int stringimplode(Constant* con);
Constant cloneconstant(Constant* con); /* shallow clone*/
Constant gen_stringall(unsigned long size, Datasrc* src, unsigned long);
Constant* emptycompoundconst(int,Constant*);
Constant* emptystringconst(int,Constant*);
Datasrc* datalist2src(Datalist* list);
Datasrc* const2src(Constant*);
Constant list2const(Datalist*);
@ -155,28 +106,29 @@ void freedatasrc(Datasrc* src);
void srcpush(Datasrc*);
void srcpushlist(Datasrc* src, Datalist* cmpd);
void srcpop(Datasrc*);
void srcmoveto(Datasrc*,size_t);
void srcmove(Datasrc*,size_t);
void srcsetfill(Datasrc* ds, Datalist* list);
Datalist* datalistclone(Datalist* dl);
Datalist* datalistconcat(Datalist* dl1, Datalist* dl2);
Datalist* datalistappend(Datalist* dl, Constant* con);
Datalist* datalistreplace(Datalist* dl, unsigned int index, Constant* con);
int datalistline(Datalist*);
int datalistline(Datalist*);
#define datalistith(dl,i) ((dl)==NULL?NULL:((i) >= (dl)->length?NULL:&(dl)->data[i]))
Constant* srcnext(Datasrc*);
int srclast(Datasrc*); /* are we at the last entry ? */
int srcmore(Datasrc*);
int srcline(Datasrc* ds);
void srcsplice(Datasrc* ds, Datalist* list);
#define islistconst(con) ((con)!=NULL && (con)->nctype == NC_COMPOUND)
#define isfillconst(con) ((con)!=NULL && (con)->nctype == NC_FILLVALUE)
#define constline(con) (con==NULL?0:(con)->lineno)
Constant* emptystringconst(int,Constant*);
Constant cloneconstant(Constant* con); /* shallow clone*/
void alignbuffer(struct Constant* prim, Bytebuffer* buf);
/* Code dump support procedures */
void bbindent(Bytebuffer*,const int);
void bbprintf(Bytebuffer*,const char *fmt, ...);
void bbprintf0(Bytebuffer*,const char *fmt, ...);
void bbprintf(Bytebuffer*,const char *fmt, ...); /* append */
void bbprintf0(Bytebuffer*,const char *fmt, ...); /* clear, then append*/
/* Following dump to codebuffer */
void codeprintf(const char *fmt, ...);
void codedump(Bytebuffer*);
@ -206,13 +158,37 @@ extern Constant nullconstant;
extern Constant fillconstant;
/* From genchar.c */
void gen_charattr(struct Symbol* asym, Bytebuffer* databuf);
void gen_chararray(struct Symbol* vsym, Datasrc*, Bytebuffer* databuf, Datalist* fillsrc);
void gen_charfield(Datasrc* src, Odometer*, Bytebuffer* databuf);
void gen_charvlen(Datasrc*, Bytebuffer*);
int collectstring(struct Constant*, size_t, Bytebuffer*, int);
int getfillchar(Datalist* fillsrc);
int buildcanonicalcharlist(Datalist*, size_t, int, Constant*);
void padstring(Constant* con, size_t desiredlength, int fillchar);
void gen_charattr(Datalist*, Bytebuffer*);
void gen_charvlen(Datalist*, Bytebuffer*);
void gen_chararray(struct Dimset*, Datalist*, Bytebuffer*, Datalist* fillsrc);
/* Mnemonic */
#define UNKNOWN ((size_t)0)
typedef enum ListClass {
LISTDATA, LISTATTR, LISTVLEN, LISTCOMPOUND, LISTFIELDARRAY
} ListClass;
struct Generator {
void* state;
int (*charconstant)(Generator*,Bytebuffer*,...);
int (*constant)(Generator*,Constant*,Bytebuffer*,...);
int (*listbegin)(Generator*,ListClass,size_t,Bytebuffer*,int*,...);
int (*list)(Generator*,ListClass,int,size_t,Bytebuffer*,...);
int (*listend)(Generator*,ListClass,int,size_t,Bytebuffer*,...);
int (*vlendecl)(Generator*,Bytebuffer*,struct Symbol*,int,size_t,...);
int (*vlenstring)(Generator*,Bytebuffer*,int*,size_t*,...);
};
extern int generator_getstate(Generator*,void**);
extern int generator_reset(Generator*,void*);
typedef int (*Writer)(Generator*,struct Symbol*,Bytebuffer*,int,size_t*,size_t*);
extern void generate_attrdata(struct Symbol*, Generator*, Writer writer, Bytebuffer*);
extern void generate_vardata(struct Symbol*, Generator*, Writer writer,Bytebuffer*);
extern void generate_basetype(struct Symbol*,Constant*,Bytebuffer*,Datalist*,Generator*);
#endif /*DATA_H*/

View File

@ -1,8 +1,6 @@
#ifndef NCGEN_DEBUG_H
#define NCGEN_DEBUG_H
/*#define F*/
/*********************************************************************
* Copyright 1993, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
@ -14,6 +12,26 @@
#include "generr.h"
#include "bytebuffer.h"
#if 0
#define GENDEBUG 2
#endif
#ifdef GENDEBUG
# define DEBUG
# if GENDEBUG > 0
# define DEBUG1
# endif
# if GENDEBUG > 1
# define DEBUG2
# endif
# if GENDEBUG > 2
# define DEBUG3
# endif
#endif
extern int ncgdebug;
extern int debug;

8
ncgen/env Normal file
View File

@ -0,0 +1,8 @@
L="-lc"
K="-k3"
alias q0="./ncgen -d $K $L test.cdl"
alias qq="gdb --args ./ncgen -d $K $L test.cdl"
alias qv="valgrind --leak-check=full ./ncgen -d $K $L test.cdl"

View File

@ -19,56 +19,54 @@ static void initdecodify(void);
void
expand_escapes(
char *termstring, /* returned, with escapes expanded */
Bytebuffer *s, /* fill with contents of yytext, with escapes expanded */
char *yytext,
int yyleng)
{
char *s, *t, *endp;
char *t, *endp;
yytext[yyleng-1]='\0'; /* don't copy quotes */
/* expand "\" escapes, e.g. "\t" to tab character */
s = termstring;
t = yytext+1;
while(*t) {
if (*t == '\\') {
t++;
switch (*t) {
case 'a':
*s++ = '\007'; t++; /* will use '\a' when STDC */
bbAppend(s,'\007'); t++; /* will use '\a' when STDC */
break;
case 'b':
*s++ = '\b'; t++;
bbAppend(s,'\b'); t++;
break;
case 'f':
*s++ = '\f'; t++;
bbAppend(s,'\f'); t++;
break;
case 'n':
*s++ = '\n'; t++;
bbAppend(s,'\n'); t++;
break;
case 'r':
*s++ = '\r'; t++;
bbAppend(s,'\r'); t++;
break;
case 't':
*s++ = '\t'; t++;
bbAppend(s,'\t'); t++;
break;
case 'v':
*s++ = '\v'; t++;
bbAppend(s,'\v'); t++;
break;
case '\\':
*s++ = '\\'; t++;
bbAppend(s,'\\'); t++;
break;
case '?':
*s++ = '\177'; t++;
bbAppend(s,'\177'); t++;
break;
case '\'':
*s++ = '\''; t++;
bbAppend(s,'\''); t++;
break;
case '\"':
*s++ = '\"'; t++;
bbAppend(s,'\"'); t++;
break;
case 'x':
t++; /* now t points to one or more hex digits */
*s++ = (char) strtol(t, &endp, 16);
bbAppend(s,(char) strtol(t, &endp, 16));
t = endp;
break;
case '0':
@ -80,18 +78,19 @@ expand_escapes(
case '6':
case '7':
/* t now points to octal digits */
*s++ = (char) strtol(t, &endp, 8);
bbAppend(s,(char) strtol(t, &endp, 8));
t = endp;
break;
default:
*s++ = *t++;
bbAppend(s,*t); t++;
break;
}
} else {
*s++ = *t++;
bbAppend(s,*t); t++;
}
}
*s = '\0';
bbNull(s);
bbSetlength(s,strlen(bbContents(s)));
return;
}
@ -101,7 +100,7 @@ expand_escapes(
*/
/* ?? This seems redundant over expand_escapes*/
void
deescapify(char *name)
deescapify(char* name)
{
const char *cp = name;
char *sp;
@ -203,13 +202,13 @@ escapifyname(char* s0)
}
void
cquotestring(Bytebuffer* databuf)
cquotestring(Bytebuffer* databuf, char quote)
{
char* escaped = escapify(bbContents(databuf),'"',bbLength(databuf));
bbClear(databuf);
bbAppend(databuf,'"');
bbAppend(databuf,quote);
bbCat(databuf,escaped);
bbAppend(databuf,'"');
bbAppend(databuf,quote);
}
/*

View File

@ -2,143 +2,38 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: f77data.c,v 1.4 2010/05/24 19:59:57 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/f77data.c,v 1.4 2010/05/24 19:59:57 dmh Exp $ */
#include "includes.h"
#include "offsets.h"
#include "nciter.h"
#ifdef ENABLE_F77
/* Forward*/
static void f77data_primdata(Symbol*, Datasrc*, Bytebuffer*, Datalist*);
#include <math.h>
int f77_uid = 0;
/**************************************************/
/* Code for generating FORTRAN 77 language data lists*/
/**************************************************/
/* Datalist rules: see the rules on the man page */
/* Specialty wrappers for f77data_data */
void
f77data_attrdata(Symbol* asym, Bytebuffer* databuf)
static int
f77_charconstant(Generator* generator, Bytebuffer* codebuf, ...)
{
Datasrc* src;
int typecode = asym->typ.basetype->typ.typecode;
if(asym->data == NULL) return;
if(typecode == NC_CHAR) {
gen_charattr(asym,databuf);
} else {
src = datalist2src(asym->data);
while(srcmore(src)) {
bbAppend(databuf,' ');
f77data_basetype(asym->typ.basetype,src,databuf,NULL);
}
}
/* Escapes and quoting will be handled in genc_write */
/* Just transfer charbuf to codebuf */
Bytebuffer* charbuf;
va_list ap;
vastart(ap,codebuf);
charbuf = va_arg(ap, Bytebuffer*);
va_end(ap);
bbNull(charbuf);
bbCatbuf(codebuf,charbuf);
return 1;
}
void
f77data_array(Symbol* vsym,
Bytebuffer* databuf,
Datasrc* src,
Odometer* odom,
int index,
Datalist* fillsrc)
{
int i;
int rank = odom->rank;
int firstdim = (index == 0); /* last dimension*/
int lastdim = (index == (rank - 1)); /* last dimension*/
size_t count;
Symbol* basetype = vsym->typ.basetype;
int isunlimited = (odom->declsize[index] == 0);
int pushed=0;
ASSERT(index >= 0 && index < rank);
count = odom->count[index];
if(!firstdim && isunlimited && issublist(src)) {
srcpush(src);
pushed = 1;
}
if(lastdim) {
for(i=0;i<count;i++) {
f77data_basetype(basetype,src,databuf,fillsrc);
}
} else {
/* now walk count elements and generate recursively */
for(i=0;i<count;i++) {
f77data_array(vsym,databuf,src,odom,index+1,fillsrc);
}
}
if(isunlimited && pushed) srcpop(src);
return;
}
/* Generate an instance of the basetype using datasrc */
void
f77data_basetype(Symbol* tsym, Datasrc* datasrc, Bytebuffer* codebuf, Datalist* fillsrc)
{
switch (tsym->subclass) {
case NC_PRIM:
if(issublist(datasrc)) {
semerror(srcline(datasrc),"Expected primitive found {..}");
}
bbAppend(codebuf,' ');
f77data_primdata(tsym,datasrc,codebuf,fillsrc);
break;
default: PANIC1("f77data_basetype: unexpected subclass %d",tsym->subclass);
}
}
static void
f77data_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* codebuf, Datalist* fillsrc)
{
Constant* prim;
Constant target;
prim = srcnext(src);
if(prim == NULL) prim = &fillconstant;
ASSERT(prim->nctype != NC_COMPOUND);
if(prim->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(basetype,fillsrc);
ASSERT(filler->length == 1);
srcpushlist(src,filler);
bbAppend(codebuf,' ');
f77data_primdata(basetype,src,codebuf,NULL);
srcpop(src);
goto done;
}
target.nctype = basetype->typ.typecode;
convert1(prim,&target);
bbCat(codebuf,f77data_const(&target));
done:
return;
}
/* Result is a pool string or a constant => do not free*/
char*
f77data_const(Constant* ci)
static int
f77_constant(Generator* generator, Constant* ci, Bytebuffer* codebuf,...)
{
char tmp[64];
char* result = NULL;
tmp[0] = '\0';
char* special = NULL;
switch (ci->nctype) {
case NC_CHAR:
{
strcpy(tmp,"'");
@ -169,17 +64,76 @@ f77data_const(Constant* ci)
Bytebuffer* buf = bbNew();
bbAppendn(buf,ci->value.stringv.stringv,ci->value.stringv.len);
f77quotestring(buf);
result = bbDup(buf);
special = bbDup(buf);
bbFree(buf);
goto done;
}
break;
default: PANIC1("ncstype: bad type code: %d",ci->nctype);
default: PANIC1("f77data: bad type code: %d",ci->nctype);
}
result = pooldup(tmp);
done:
return result; /*except for NC_STRING and NC_OPAQUE*/
if(special != NULL)
bbCat(codebuf,special);
else
bbCat(codebuf,tmp);
return 1;
}
static int
f77_listbegin(Generator* generator, ListClass lc, size_t size, Bytebuffer* codebuf, int* uidp, ...)
{
if(uidp) *uidp = ++f77_uid;
return 1;
}
static int
f77_list(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* codebuf, ...)
{
switch (lc) {
case LISTATTR:
if(count > 0) bbCat(codebuf,", ");
break;
case LISTDATA:
bbAppend(codebuf,' ');
break;
case LISTVLEN:
case LISTCOMPOUND:
case LISTFIELDARRAY:
break;
}
return 1;
}
static int
f77_listend(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
{
return 1;
}
static int
f77_vlendecl(Generator* generator, Bytebuffer* codebuf, Symbol* tsym, int uid, size_t count, ...)
{
return 1;
}
static int
f77_vlenstring(Generator* generator, Bytebuffer* vlenmem, int* uidp, size_t* countp,...)
{
if(uidp) *uidp = ++f77_uid;
return 1;
}
/* Define the single static bin data generator */
static Generator f77_generator_singleton = {
NULL,
f77_charconstant,
f77_constant,
f77_listbegin,
f77_list,
f77_listend,
f77_vlendecl,
f77_vlenstring
};
Generator* f77_generator = &f77_generator_singleton;
#endif /*ENABLE_F77*/

55
ncgen/foo.cdl Normal file
View File

@ -0,0 +1,55 @@
netcdf foo { // an example netCDF specification in CDL
types:
ubyte enum enum_t {Clear = 0, Cumulonimbus = 1, Stratus = 2};
opaque(11) opaque_t;
int(*) vlen_t;
dimensions:
lat = 10 ;
lon = 5 ;
time = unlimited ; // (0) currently)
variables:
int lat(lat) ;
int lon(lon) ;
int time(time) ;
float Z(time, lat, lon) ;
float t(time, lat, lon) ;
double p(time,lat,lon);
long rh(time,lat,lon);
string country(time,lat,lon);
ubyte tag;
// variable attributes
lat:long_name = "latitude";
lat:units = "degrees_north";
lon:long_name = "longitude";
lon:units = "degrees_east";
time:units = "seconds since 1992-1-1 00:00:00";
// typed variable attributes
string Z:units = "geopotential meters";
float Z:valid_range = 0., 5000.;
double p:_FillValue = -9999.;
long rh:_FillValue = -1;
vlen_t :globalatt = {17, 18, 19};
data:
lat = 0, 10, 20, 30, 40, 50, 60, 70, 80, 90;
lon = -140, -118, -96, -84, -52;
group: g {
types:
compound cmpd_t { vlen_t f1; enum_t f2;};
} // group g
group: h {
variables:
/g/cmpd_t compoundvar;
data:
compoundvar = { {3,4,5}, Stratus } ;
} // group h
}//foo

View File

@ -6,8 +6,6 @@
#include "includes.h"
#include <ctype.h> /* for isprint() */
#include "nciter.h"
#include "offsets.h"
#ifdef ENABLE_BINARY
@ -18,9 +16,11 @@ extern List* vlenconstants;
#endif
/* Forward*/
static void genbin_defineattr(Symbol* asym,Bytebuffer*);
static void genbin_defineattr(Symbol* asym);
static void genbin_definevardata(Symbol* vsym);
static void genbin_write(Symbol*,Bytebuffer*,Odometer*,int);
static int genbin_write(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static int genbin_writevar(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static int genbin_writeattr(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
#ifdef USE_NETCDF4
static void genbin_deftype(Symbol* tsym);
@ -93,7 +93,7 @@ gen_netcdf(const char *filename)
Symbol* dsym = (Symbol*)listget(dimdefs,idim);
stat = nc_def_dim(dsym->container->ncid,
dsym->name,
dsym->dim.declsize,
(dsym->dim.isunlimited?NC_UNLIMITED:dsym->dim.declsize),
&dsym->ncid);
check_err(stat,__LINE__,__FILE__);
}
@ -145,8 +145,7 @@ gen_netcdf(const char *filename)
if(ngatts > 0) {
for(iatt = 0; iatt < ngatts; iatt++) {
Symbol* gasym = (Symbol*)listget(gattdefs,iatt);
bbClear(databuf);
genbin_defineattr(gasym,databuf);
genbin_defineattr(gasym);
}
}
@ -154,8 +153,7 @@ gen_netcdf(const char *filename)
if(natts > 0) {
for(iatt = 0; iatt < natts; iatt++) {
Symbol* asym = (Symbol*)listget(attdefs,iatt);
bbClear(databuf);
genbin_defineattr(asym,databuf);
genbin_defineattr(asym);
}
}
@ -262,7 +260,6 @@ genbin_deftype(Symbol* tsym)
case NC_ENUM: {
Bytebuffer* datum;
Datalist* ecdl;
Datasrc* esrc;
stat = nc_def_enum(tsym->container->ncid,
tsym->typ.basetype->typ.typecode,
tsym->name,
@ -272,14 +269,12 @@ genbin_deftype(Symbol* tsym)
ecdl = builddatalist(1);
dlextend(ecdl); /* make room for one constant*/
ecdl->length = 1;
esrc = datalist2src(ecdl);
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* econst = (Symbol*)listget(tsym->subnodes,i);
ASSERT(econst->subclass == NC_ECONST);
ecdl->data[0] = econst->typ.econst;
esrc->index = 0;
generator_reset(bin_generator,NULL);
bbClear(datum);
bindata_basetype(econst->typ.basetype,esrc,datum,NULL);
generate_basetype(econst->typ.basetype,&econst->typ.econst,datum,NULL,bin_generator);
stat = nc_insert_enum(tsym->container->ncid,
tsym->ncid,
econst->name,
@ -287,8 +282,6 @@ genbin_deftype(Symbol* tsym)
check_err(stat,__LINE__,__FILE__);
}
bbFree(datum);
ecdl->length = 0;
freedatasrc(esrc);
} break;
case NC_VLEN:
stat = nc_def_vlen(tsym->container->ncid,
@ -340,7 +333,74 @@ genbin_deftype(Symbol* tsym)
#endif /*USE_NETCDF4*/
static void
genbin_defineattr(Symbol* asym,Bytebuffer* databuf)
genbin_defineattr(Symbol* asym)
{
Bytebuffer* databuf = bbNew();
generator_reset(bin_generator,NULL);
generate_attrdata(asym,bin_generator,(Writer)genbin_write,databuf);
}
/* Following is patterned after the walk functions in semantics.c */
static void
genbin_definevardata(Symbol* vsym)
{
Bytebuffer* databuf;
if(vsym->data == NULL) return;
databuf = bbNew();
generator_reset(bin_generator,NULL);
generate_vardata(vsym,bin_generator,(Writer)genbin_write,databuf);
}
static int
genbin_write(Generator* generator, Symbol* sym, Bytebuffer* memory,
int rank, size_t* start, size_t* count)
{
if(sym->objectclass == NC_ATT)
return genbin_writeattr(generator,sym,memory,rank,start,count);
else if(sym->objectclass == NC_VAR)
return genbin_writevar(generator,sym,memory,rank,start,count);
else
PANIC("illegal symbol for genc_write");
return NC_EINVAL;
}
static int
genbin_writevar(Generator* generator, Symbol* vsym, Bytebuffer* memory,
int rank, size_t* start, size_t* count)
{
int stat = NC_NOERR;
char* data = bbContents(memory);
#ifdef DEBUG
{
int i;
fprintf(stderr,"startset = [");
for(i=0;i<rank;i++)
fprintf(stderr,"%s%lu",(i>0?", ":""),(unsigned long)start[i]);
fprintf(stderr,"] ");
fprintf(stderr,"countset = [");
for(i=0;i<rank;i++)
fprintf(stderr,"%s%lu",(i>0?", ":""),(unsigned long)count[i]);
fprintf(stderr,"]\n");
fflush(stderr);
}
#endif
if(rank == 0) {
size_t count[1] = {1};
stat = nc_put_var1(vsym->container->ncid, vsym->ncid, count, data);
} else {
stat = nc_put_vara(vsym->container->ncid, vsym->ncid, start, count, data);
}
check_err(stat,__LINE__,__FILE__);
bbClear(memory);
return stat;
}
static int
genbin_writeattr(Generator* generator, Symbol* asym, Bytebuffer* databuf,
int rank, size_t* start, size_t* count)
{
int stat;
size_t len;
@ -348,17 +408,13 @@ genbin_defineattr(Symbol* asym,Bytebuffer* databuf)
int varid, grpid, typid;
Symbol* basetype = asym->typ.basetype;
bbClear(databuf);
grpid = asym->container->ncid,
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) {
@ -433,120 +489,20 @@ genbin_defineattr(Symbol* asym,Bytebuffer* databuf)
}
} 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)
{
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);
Datasrc* src;
#ifdef IGNORE
grpid = vsym->container->ncid,
varid = vsym->ncid;
rank = vsym->typ.dimset.ndims;
#ifdef DEBUG
{
char out[4096];
memset(out,0x77,sizeof(out));
stat = nc_get_att(grpid,varid,asym->name,&out);
check_err(stat,__LINE__,__FILE__);
}
#endif
memory = bbNew();
/* give the buffer a running start to be large enough*/
bbSetalloc(memory, nciterbuffersize);
if(vsym->data == NULL) return;
src = datalist2src(vsym->data);
/* Generate character constants separately */
if(!isscalar && chartype) {
gen_chararray(vsym,src,memory,fillsrc);
/* generate a corresponding odometer */
odom = newodometer(&vsym->typ.dimset,NULL,NULL);
genbin_write(vsym,memory,odom,0);
} else { /* not character constant */
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;i<odom->rank;i++)
fprintf(stderr,"%s%lu",(i==0?"":","),(unsigned long)odom->start[i]);
fprintf(stderr,"]\n %s->count[",vsym->name);
for(i=0;i<odom->rank;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);
/* See if we have too much data */
if(srcmore(src)) {
semerror(srcline(src),"Extra data found at end of datalist");
}
}
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;i<odom->rank;i++)
fprintf(stderr,"%s%lu",(i>0?", ":""),(unsigned long)odom->start[i]);
fprintf(stderr,"] ");
fprintf(stderr,"countset = [");
for(i=0;i<odom->rank;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);
return stat;
}
#endif /*ENABLE_BINARY*/

View File

@ -12,8 +12,6 @@
#undef TRACE
extern List* vlenconstants; /* List<Constant*>;*/
/* Forward */
static const char* groupncid(Symbol*);
static const char* typencid(Symbol*);
@ -28,9 +26,10 @@ static void genc_definespecialattributes(Symbol* vsym);
static void genc_defineattr(Symbol* asym);
static void genc_definevardata(Symbol*);
static void genc_write(Symbol*,Bytebuffer*,Odometer*,int);
static void computemaxunlimited(void);
static void genc_write(Generator*,Symbol* sym, Bytebuffer* code,
int rank, size_t* start, size_t* count);
static void genc_writevar(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static void genc_writeattr(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
/*
* Generate C code for creating netCDF from in-memory structure.
@ -90,21 +89,6 @@ gen_ncc(const char *filename)
}
codeflush();
/*
Define vlen constants
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.
*/
{
Bytebuffer* vlencode = bbNew();
codeflush(); /* dump code to this point*/
cdata_vlenconstants(vlenconstants,vlencode);
codedump(vlencode);
codeline("");
bbFree(vlencode);
}
/* Construct the chunking constants*/
if(!usingclassic) {
for(ivar=0;ivar<nvars;ivar++) {
@ -190,7 +174,7 @@ gen_ncc(const char *filename)
codelined(1,"/* dimension lengths */");
for(idim = 0; idim < ndims; idim++) {
Symbol* dsym = (Symbol*)listget(dimdefs,idim);
if(dsym->dim.declsize == NC_UNLIMITED) {
if(dsym->dim.isunlimited) {
bbprintf0(stmt,"%ssize_t %s_len = NC_UNLIMITED;\n",
indented(1),cname(dsym));
} else {
@ -311,10 +295,24 @@ gen_ncc(const char *filename)
codelined(1,"/* define dimensions */");
for(idim = 0; idim < ndims; idim++) {
Symbol* dsym = (Symbol*)listget(dimdefs,idim);
bbprintf0(stmt,
" stat = nc_def_dim(%s, \"%s\", %s_len, &%s);\n",
groupncid(dsym->container),
escapifyname(dsym->name), cname(dsym), dimncid(dsym));
#ifdef IGNORE
if(dsym->dim.isunlimited) {
bbprintf0(stmt,
" stat = nc_def_dim(%s, \"%s\", %s, &%s);\n",
groupncid(dsym->container),
escapifyname(dsym->name),
"NC_UNLIMITED",
dimncid(dsym));
} else
#endif
{
bbprintf0(stmt,
" stat = nc_def_dim(%s, \"%s\", %s_len, &%s);\n",
groupncid(dsym->container),
escapifyname(dsym->name),
cname(dsym),
dimncid(dsym));
}
codedump(stmt);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
}
@ -406,8 +404,6 @@ gen_ncc(const char *filename)
if(vsym->data != NULL) genc_definevardata(vsym);
}
codeline("");
/* compute the max actual size of the unlimited dimension*/
if(usingclassic) computemaxunlimited();
}
codeflush();
}
@ -500,23 +496,6 @@ cl_c(void)
*/
#define INDENTMAX 256
static char* dent = NULL;
char*
indented(int n)
{
char* indentation;
if(dent == NULL) {
dent = (char*)emalloc(INDENTMAX+1);
memset((void*)dent,' ',INDENTMAX);
dent[INDENTMAX] = '\0';
}
if(n*4 >= INDENTMAX) n = INDENTMAX/4;
indentation = dent+(INDENTMAX - 4*n);
return indentation;
}
/* return C name for netCDF type, given type code */
const char *
@ -713,11 +692,15 @@ definectype(Symbol* tsym)
case NC_ENUM:
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* econst = (Symbol*)listget(tsym->subnodes,i);
Bytebuffer* econststring = bbNew();
ASSERT(econst->subclass == NC_ECONST);
c_generator->constant(c_generator,&econst->typ.econst,econststring);
bbNull(econststring);
bbprintf0(stmt,"#define %s ((%s)%s)\n",
cname(econst),
ctypename(econst->typ.basetype),
cdata_const(&econst->typ.econst));
bbContents(econststring));
bbFree(econststring);
codedump(stmt);
}
bbprintf0(stmt,"typedef %s %s;\n",
@ -806,9 +789,13 @@ genc_deftype(Symbol* tsym)
codelined(1,"check_err(stat,__LINE__,__FILE__);");
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* econst = (Symbol*)listget(tsym->subnodes,i);
Bytebuffer* econststring = bbNew();
ASSERT(econst->subclass == NC_ECONST);
c_generator->constant(c_generator,&econst->typ.econst,econststring);
bbNull(econststring);
bbprintf0(stmt,"%seconst = %s;\n",
indented(1),cdata_const(&econst->typ.econst));
indented(1),bbContents(econststring));
bbFree(econststring);
codedump(stmt);
bbprintf0(stmt,"%sstat = nc_insert_enum(%s, %s, \"%s\", &econst);\n",
indented(1),
@ -907,32 +894,201 @@ genc_deftype(Symbol* tsym)
static void
genc_defineattr(Symbol* asym)
{
unsigned long len;
Datalist* list;
Symbol* basetype = asym->typ.basetype;
Bytebuffer* code = NULL; /* capture other decls*/
/* we need to capture vlen strings for dumping */
Bytebuffer* save = bbNew(); /* capture so we can dump
vlens first */
List* oldstate = NULL;
generator_getstate(c_generator,(void*)&oldstate);
listfree(oldstate);
generator_reset(c_generator,(void*)listnew());
generate_attrdata(asym,c_generator,(Writer)genc_write,save);
bbFree(save);
}
static void
genc_definevardata(Symbol* vsym)
{
Bytebuffer* save; /* capture so we can dump vlens first */
List* oldstate = NULL;
if(vsym->data == NULL) return;
save = bbNew();
generator_getstate(c_generator,(void*)&oldstate);
listfree(oldstate);
generator_reset(c_generator,(void*)listnew());
generate_vardata(vsym,c_generator,(Writer)genc_write,save);
bbFree(save);
}
static void
genc_write(Generator* generator, Symbol* sym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
if(sym->objectclass == NC_ATT)
genc_writeattr(generator,sym,code,rank,start,count);
else if(sym->objectclass == NC_VAR)
genc_writevar(generator,sym,code,rank,start,count);
else
PANIC("illegal symbol for genc_write");
}
static void
genc_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Symbol* basetype = vsym->typ.basetype;
nc_type typecode = basetype->typ.typecode;
List* vlendecls;
list = asym->data;
len = list==NULL?0:list->length;
/* define a block to avoid name clashes*/
codeline("");
codelined(1,"{");
bbprintf0(stmt,"%s{ /* %s */\n",indented(1),asym->name);
codedump(stmt);
/* Dump any vlen decls first */
generator_getstate(generator,(void**)&vlendecls);
if(vlendecls != NULL && listlength(vlendecls) > 0) {
int i;
for(i=0;i<listlength(vlendecls);i++) {
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
codelined(1,bbContents(decl));
bbFree(decl);
}
listfree(vlendecls);
generator_reset(generator,NULL);
}
code = bbNew();
cdata_attrdata(asym,code);
if(rank == 0) {
codelined(1,"size_t zero = 0;");
if(typecode == NC_CHAR) {
cquotestring(code,'"');
bbprintf0(stmt,"%sstatic char* %s_data = %s;\n",
indented(1),
cname(vsym),
bbContents(code));
} else {
/* We make the data be an array so we do not need to
ampersand it later => we need an outer pair of braces
*/
commify(code); /* insert commas at proper places */
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
indented(1),
ctypename(basetype),
cname(vsym),
bbContents(code));
}
codedump(stmt);
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &zero, %s_data);\n",
indented(1),
groupncid(vsym->container),
varncid(vsym),
cname(vsym));
codedump(stmt);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
codeflush();
} else { /* rank > 0 */
int i;
size_t length = 0;
if(typecode == NC_CHAR) {
length = bbLength(code);
/* generate data constant */
bbprintf(stmt,"%schar* %s_data = ",
indented(1),
cname(vsym),
(unsigned long)length);
codedump(stmt);
cquotestring(code,'"');
codedump(code);
codeline(" ;");
} else {
/* Compute total size */
length = 1;
for(i=0;i<rank;i++) length *= count[i];
/* generate data constant */
commify(code); /* insert commas at proper places */
bbprintf(stmt,"%s%s %s_data[%lu] = ",
indented(1),
ctypename(basetype),
cname(vsym),
(unsigned long)length);
codedump(stmt);
/* C requires an outer set of braces on datalist constants */
codepartial("{");
codedump(code);
codeline("} ;");
}
/* generate constants for startset, countset*/
bbprintf0(stmt,"%ssize_t %s_startset[%lu] = {",
indented(1),
cname(vsym),
rank);
for(i=0;i<rank;i++) {
bbprintf(stmt,"%s%lu",(i>0?", ":""),start[i]);
}
codedump(stmt);
codeline("} ;");
bbprintf0(stmt,"%ssize_t %s_countset[%lu] = {",
indented(1),
cname(vsym),
rank);
for(i=0;i<rank;i++) {
bbprintf(stmt,"%s%lu",(i>0?", ":""),count[i]);
}
codedump(stmt);
codeline("};");
bbprintf0(stmt,"%sstat = nc_put_vara(%s, %s, %s_startset, %s_countset, %s_data);\n",
indented(1),
groupncid(vsym->container), varncid(vsym),
cname(vsym),
cname(vsym),
cname(vsym));
codedump(stmt);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
}
/* end defined block*/
codelined(1,"}\n");
codeflush();
}
static void
genc_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Symbol* basetype = asym->typ.basetype;
int typecode = basetype->typ.typecode;
size_t len = asym->data->length; /* default assumption */
/* define a block to avoid name clashes*/
codeline("");
codelined(1,"{");
/* Handle NC_CHAR specially */
if(typecode == NC_CHAR) {
len = bbLength(code);
len = bbLength(code); /* presumably before quoting */
/* Revise length if length == 0 */
if(len == 0) len++;
cquotestring(code);
bbNull(code);
cquotestring(code,'"');
} else {
/* All other cases */
/* Dump any vlen decls first */
List* vlendecls;
generator_getstate(generator,(void**)&vlendecls);
if(vlendecls != NULL && listlength(vlendecls) > 0) {
int i;
for(i=0;i<listlength(vlendecls);i++) {
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
codelined(1,bbContents(decl));
bbFree(decl);
}
listfree(vlendecls);
generator_reset(generator,NULL);
}
commify(code);
bbprintf0(stmt,"%sstatic const %s %s_att[%ld] = ",indented(1),
bbprintf0(stmt,"%sstatic const %s %s_att[%ld] = ",
indented(1),
ctypename(basetype),
cname(asym),
asym->data->length
@ -946,7 +1102,6 @@ genc_defineattr(Symbol* asym)
}
/* Use the specialized put_att_XX routines if possible*/
/*defatt:*/
switch (basetype->typ.typecode) {
case NC_BYTE:
case NC_SHORT:
@ -1029,7 +1184,7 @@ genc_defineattr(Symbol* asym)
if(usingclassic && !isclassicprim(basetype->typ.typecode)) {
verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
}
bbprintf0(stmt,"%sstat = nc_put_att(%s, %s, \"%s\", %s, %lu, %s_att);",
bbprintf0(stmt,"%sstat = nc_put_att(%s, %s, \"%s\", %s, %lu, %s_att);\n",
indented(1),
groupncid(asym->container),
(asym->att.var == NULL?"NC_GLOBAL"
@ -1043,169 +1198,7 @@ genc_defineattr(Symbol* asym)
break;
}
bbFree(code);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
codelined(1,"}");
}
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;i<listlength(vardefs);i++) {
Symbol* dim;
Symbol* var = (Symbol*)listget(vardefs,i);
if(var->typ.dimset.ndims == 0) continue; /* rank == 0*/
dim = var->typ.dimset.dimsyms[0];
if(dim->dim.declsize != NC_UNLIMITED) continue; /* var does not use unlimited*/
if(var->typ.dimset.dimsyms[0]->dim.declsize > maxsize)
maxsize = var->typ.dimset.dimsyms[0]->dim.declsize;
}
}
static void
genc_definevardata(Symbol* vsym)
{
Dimset* dimset = &vsym->typ.dimset;
int isscalar = (dimset->ndims == 0);
Bytebuffer* code = NULL;
Datasrc* src = NULL;
Datalist* fillsrc = NULL;
nciter_t iter;
Odometer* odom = NULL;
size_t nelems;
int chartype = (vsym->typ.basetype->typ.typecode == NC_CHAR);
if(vsym->data == NULL) return;
src = datalist2src(vsym->data);
code = bbNew();
/* give the buffer a running start to be large enough*/
bbSetalloc(code, nciterbuffersize);
if(!isscalar && chartype) {
gen_chararray(vsym,src,code,fillsrc);
/* generate a corresponding odometer */
odom = newodometer(&vsym->typ.dimset,NULL,NULL);
/* patch the odometer to use the right counts */
genc_write(vsym,code,odom,0);
} else { /* not character constant */
fillsrc = vsym->var.special._Fillvalue;
/* Handle special cases first*/
if(isscalar) {
cdata_basetype(vsym->typ.basetype,src,code,fillsrc);
commify(code);
genc_write(vsym,code,NULL,1);
} else { /* Non-scalar*/
/* 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;
cdata_array(vsym,code,src,odom,/*index=*/0,fillsrc);
commify(code);
genc_write(vsym,code,odom,0);
}
}
}
if(odom != NULL) odometerfree(odom);
bbFree(code);
}
static void
genc_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar)
{
Symbol* basetype = vsym->typ.basetype;
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
int chartype = (vsym->typ.basetype->typ.typecode == NC_CHAR);
if(isscalar) {
codelined(1,"{");
codelined(1,"size_t zero = 0;");
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
indented(1),
ctypename(basetype),
cname(vsym),
bbContents(code));
codedump(stmt);
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &zero, %s_data);",
indented(1),
groupncid(vsym->container),
varncid(vsym),
cname(vsym));
codedump(stmt);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
codelined(1,"}");
} else {
int i;
size_t count = 0;
if(chartype)
count = bbLength(code);
else
count = odometertotal(odom,0);
/* define a block to avoid name clashes*/
bbprintf0(stmt,"%s{\n",indented(1));
/* generate data constant */
bbprintf(stmt,"%s%s %s_data[%lu] = ",
indented(1),
ctypename(basetype),
cname(vsym),
(unsigned long)count);
codedump(stmt);
if(chartype) {
cquotestring(code);
codedump(code);
codeline(" ;");
} else {
/* C requires an outer set of braces on datalist constants */
codepartial("{");
codedump(code);
codeline("} ;");
}
/* generate constants for startset, countset*/
bbprintf0(stmt,"%ssize_t %s_startset[%lu] = {",
indented(1),
cname(vsym),
rank);
for(i=0;i<rank;i++) {
bbprintf(stmt,"%s%lu",(i>0?", ":""),odom->start[i]);
}
codedump(stmt);
codeline("} ;");
bbprintf0(stmt,"%ssize_t %s_countset[%lu] = {",
indented(1),
cname(vsym),
rank);
for(i=0;i<rank;i++) {
bbprintf(stmt,"%s%lu",(i>0?", ":""),odom->count[i]);
}
codedump(stmt);
codeline("} ;");
bbprintf0(stmt,"%sstat = nc_put_vara(%s, %s, %s_startset, %s_countset, %s_data);\n",
indented(1),
groupncid(vsym->container), varncid(vsym),
cname(vsym),
cname(vsym),
cname(vsym));
codedump(stmt);
codelined(1,"check_err(stat,__LINE__,__FILE__);");
/* end defined block*/
codelined(1,"}\n");
}
}
#endif /*ENABLE_C*/

View File

@ -2,8 +2,6 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: genchar.c,v 1.6 2010/05/24 19:59:57 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/genchar.c,v 1.6 2010/05/24 19:59:57 dmh Exp $ */
#include "includes.h"
@ -12,6 +10,10 @@
language independent */
/******************************************************/
static size_t gen_charconstant(Constant*, Bytebuffer*, int fillchar);
static int getfillchar(Datalist* fillsrc);
static void gen_chararrayr(Dimset*,int,int,Bytebuffer*,Datalist*,int,int,int);
/*
Matching strings to char variables, attributes, and vlen
constants is challenging because it is desirable to mimic
@ -19,338 +21,171 @@ the original ncgen. The "algorithms" used there have no
simple characterization (such as "abc" == {'a','b','c'}).
So, this rather ugly code is kept in this file
and a variety of heuristics are used to mimic ncgen.
The core algorithm is as follows.
1. Assume we have a set of dimensions D1..Dn,
where D1 may optionally be an Unlimited dimension.
It is assumed that the sizes of the Di are all known.
2. Given a sequence of string or character constants
C1..Cm, our goal is to construct a single string
whose length is the cross product of D1 thru Dn.
3. For purposes of this algorithm, character constants
are treated as strings of size 1.
4. Construct Dx = cross product of D1 thru D(n-1).
5. For each constant Ci, add fill characters, if necessary,
so that its length is a multiple of Dn.
6. Concatenate the modified C1..Cm to produce string S.
7. Add fill characters to S to make its size be a multiple of
Dn.
8. If S is longer than the Dx * Dn, then truncate
and generate a warning.
Two other cases:
1. character vlen: char(*) vlen_t.
For this case, we simply concat all the elements.
2. character attribute.
For this case, we simply concat all the elements.
*/
static void gen_chararrayr(Dimset*, Bytebuffer*, int index, Datasrc*, int fillchar, size_t);
void
gen_chararray(Dimset* dimset, Datalist* data, Bytebuffer* databuf, Datalist* fillsrc)
{
int ndims,lastunlim;
int fillchar = getfillchar(fillsrc);
size_t expectedsize,xproduct;
size_t unitsize;
extern List* vlenconstants;
ASSERT(bbLength(databuf) == 0);
ndims = dimset->ndims;
/* Find the last unlimited */
lastunlim = findlastunlimited(dimset);
if(lastunlim < 0) lastunlim = 0; /* pretend */
/* Compute crossproduct upto the last dimension,
starting at the last unlimited
*/
xproduct = crossproduct(dimset,lastunlim,ndims-1);
if(ndims == 0) {
unitsize = 1;
} else if(lastunlim == ndims-1) {/* last dimension is unlimited */
unitsize = 1;
} else { /* last dim is not unlimited */
unitsize = dimset->dimsyms[ndims-1]->dim.declsize;
}
expectedsize = (xproduct * unitsize);
gen_chararrayr(dimset,0,lastunlim,databuf,data,fillchar,unitsize,expectedsize);
}
/* Recursive helper */
static void
gen_chararrayr(Dimset* dimset, int dimindex, int lastunlimited,
Bytebuffer* databuf, Datalist* data, int fillchar,
int unitsize, int expectedsize)
{
int i;
if(dimindex < lastunlimited) {
/* keep recursing */
for(i=0;i<data->length;i++) {
Constant* c = datalistith(data,i);
ASSERT(islistconst(c));
gen_chararrayr(dimset,dimindex+1,lastunlimited,databuf,
c->value.compoundv,fillchar,unitsize,expectedsize);
}
} else {/* we are at a list of simple constants */
for(i=0;i<data->length;i++) {
Constant* c = datalistith(data,i);
ASSERT(!islistconst(c));
if(isstringable(c->nctype)) {
int j;
size_t constsize;
constsize = gen_charconstant(c,databuf,fillchar);
if(constsize % unitsize > 0) {
size_t padsize = unitsize - (constsize % unitsize);
for(j=0;j<padsize;j++) bbAppend(databuf,fillchar);
}
} else {
semwarn(constline(c),
"Encountered non-string and non-char constant in datalist; ignored");
}
}
}
/* If |databuf| > expectedsize, complain: exception is zero length */
if(bbLength(databuf) == 0 && expectedsize == 1) {
/* this is okay */
} else if(bbLength(databuf) > expectedsize) {
semwarn(data->data[0].lineno,"character data list too long");
} else {
size_t bufsize = bbLength(databuf);
/* Pad to size dimproduct size */
if(bufsize % expectedsize > 0) {
size_t padsize = expectedsize - (bufsize % expectedsize);
for(i=0;i<padsize;i++) bbAppend(databuf,fillchar);
}
}
}
void
gen_charattr(Symbol* asym, Bytebuffer* databuf)
gen_charattr(Datalist* data, Bytebuffer* databuf)
{
Datasrc* src;
Constant* con;
gen_charvlen(data,databuf);
}
if(asym->data == NULL) return;
src = datalist2src(asym->data);
while((con=srcnext(src))) {
switch (con->nctype) {
/* Following list should be consistent with isstringable */
case NC_CHAR:
bbAppend(databuf,con->value.charv);
break;
case NC_BYTE:
bbAppend(databuf,con->value.int8v);
break;
case NC_UBYTE:
bbAppend(databuf,con->value.uint8v);
break;
case NC_STRING:
bbCat(databuf,con->value.stringv.stringv);
bbNull(databuf);
break;
case NC_FILL:
bbAppend(databuf,NC_FILL_CHAR);
break;
default:
semerror(srcline(src),
"Encountered non-string constant in attribute: %s",
asym->name);
void
gen_charvlen(Datalist* data, Bytebuffer* databuf)
{
int i;
Constant* c;
ASSERT(bbLength(databuf) == 0);
for(i=0;i<data->length;i++) {
c = datalistith(data,i);
if(isstringable(c->nctype)) {
(void)gen_charconstant(c,databuf,NC_FILL_CHAR);
} else {
semerror(constline(c),
"Encountered non-string and non-char constant in datalist");
return;
}
}
}
#ifdef IGNORE
static void
datalistpad(Datalist* data, size_t targetlen)
static size_t
gen_charconstant(Constant* con, Bytebuffer* databuf, int fillchar)
{
int i;
/* pad this datalist to target length */
for(i=data->length;i<targetlen;i++) {
Constant ccon,scon;
Datalist* sublist;
ccon.nctype = NC_COMPOUND;
ccon.lineno = 0;
ccon.filled = 0;
ccon.value.compoundv = builddatalist(1);
scon.value.stringv.len = 0;
scon.value.stringv.stringv = strdup("");
scon.nctype = NC_STRING;
scon.lineno = 0;
scon.filled = 0;
sublist = ccon.value.compoundv;
dlappend(sublist,&scon);
}
}
#endif
/*Note see comment before semantics.c:walkchararray.
This code finishes off the processing in those comments.
In particular, at this point, the sizes of all
unlimited is known. Assuming the same set of
cases as in that comment, we do the additional actions.
Cases:
1. the variable's dimension set has no unlimiteds
Action:
1. do nothing
2. the dimension set has one or more unlimiteds.
This means that we have to recursively deal with
nested compound instances.
The last (rightmost) unlimited will correspond
to a sequence of stringables.
This has two special subcases
2a. the last dimension IS NOT unlimited
Actions:
1. pad the concat to the size of the last dimension
2b. the last dimension IS unlimited
Actions:
1. pad the concata to the actual unlimited size
3. For each dimension to the left of the last
unlimited, there are two cases.
3a. dimension is NOT unlimited
ACTION:
1. pad
3b. dimension IS unlimited
ACTION:
1. pad
*/
void
gen_chararray(Symbol* vsym, Datasrc* data, Bytebuffer* databuf, Datalist* fillsrc)
{
int i,fillchar = getfillchar(fillsrc);
int lastunlimitedindex = lastunlimited(&vsym->typ.dimset);
/* If there is no unlimited, then treat similarly to a field array */
if(lastunlimitedindex < 0) {
/* Semantics.c:walkchararray will have done all the hard work */
while(srcmore(data)) {
Constant* con = srcnext(data);
ASSERT(con->nctype == NC_STRING);
bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
}
} else {/* dimset has at least 1 unlimited */
/* Compute sub array size for extensions */
size_t subsize;
Dimset* dimset = &vsym->typ.dimset;
for(subsize=1,i=lastunlimitedindex+1;i<dimset->ndims;i++) {
Symbol* dim = dimset->dimsyms[i];
size_t declsize = dim->dim.declsize;
subsize *= (declsize == NC_UNLIMITED ? dim->dim.unlimitedsize : declsize);
}
gen_chararrayr(&vsym->typ.dimset, databuf, 0, data, fillchar, subsize);
}
bbNull(databuf);
}
static void
gen_chararrayr(Dimset* dimset, Bytebuffer* databuf, int index, Datasrc* data,
int fillchar, size_t subsize)
{
int i;
Symbol* dim = dimset->dimsyms[index];
int isunlimited = dim->dim.declsize == NC_UNLIMITED;
int lastunlimitedindex = lastunlimited(dimset);
/* Split on last unlimited */
if(index == lastunlimitedindex) {
Constant* con;
/* pad to the unlimited size of the dimension * subsize */
ASSERT(srcmore(data));
con = srcnext(data);
ASSERT(con->nctype == NC_STRING);
padstring(con,dim->dim.unlimitedsize*subsize,fillchar);
bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
} else {/* index < lastunlimitedindex*/
/* data should be a set of compounds */
size_t expected = (isunlimited ? dim->dim.unlimitedsize : dim->dim.declsize );
for(i=0;i<expected;i++) {
if(!srcmore(data)) { /* pad buffer */
int j;
for(j=0;j<subsize;j++) bbAppend(databuf,fillchar);
} else {
Datasrc* subdata;
Constant* con = srcnext(data);
if(con->nctype != NC_COMPOUND) continue;
/* recurse */
subdata = datalist2src(con->value.compoundv);
gen_chararrayr(dimset,databuf,index+1,subdata,fillchar,subsize);
}
}
}
}
/*
Since the field has fixed
dimensions, we can just
read N elements where N
is the product of the dimensions.
*/
void
gen_charfield(Datasrc* src, Odometer* odom, Bytebuffer* fieldbuf)
{
Constant* con = srcnext(src);
/* Semantics.c:walkcharfieldarray will have done all the hard work */
ASSERT(con->nctype == NC_STRING);
bbAppendn(fieldbuf,con->value.stringv.stringv,con->value.stringv.len);
}
void
gen_charvlen(Datasrc* vlensrc, Bytebuffer* databuf)
{
Constant* con = srcnext(vlensrc);
/* Semantics.c:walkcharfieldarray will have done all the hard work */
ASSERT(con->nctype == NC_STRING);
bbAppendn(databuf,con->value.stringv.stringv,con->value.stringv.len);
#ifdef IGNORE
int count;
Bytebuffer* vlenbuf = bbNew();
Constant* con;
count = 0;
while((con=srcnext(vlensrc)) != NULL) {
if(!isstringable(con->nctype)) {
semerror(srcline(vlensrc),
"Encountered non-string constant in vlen constant");
goto done;
}
count += collectstring(con,0,vlenbuf);
}
done:
bbFree(vlenbuf);
#endif
}
/**************************************************/
#ifdef IGNORE
static Datalist*
dividestringlist(char* s, size_t chunksize, int lineno)
{
size_t slen,div,rem;
Datalist* charlist;
Constant* chars;
if(s == NULL) s = "";
slen = strlen(s);
ASSERT(chunksize > 0);
div = slen / chunksize;
rem = slen % chunksize;
if(rem > 0) div++;
charlist = builddatalist(div);
if(!charlist) return NULL;
charlist->readonly = 0;
charlist->length = div;
chars=charlist->data;
if(slen == 0) {
/* Special case for null string */
charlist->length = 1;
chars->nctype = NC_STRING;
chars->lineno = lineno;
chars->value.stringv.len = 0;
chars->value.stringv.stringv = nulldup("");
} else
{
int i;
for(i=0;i<(div-1);i++,chars++) {
chars->nctype = NC_STRING;
chars->lineno = lineno;
chars->value.stringv.len = chunksize;
chars->value.stringv.stringv = (char*)emalloc(chunksize+1);
memcpy(chars->value.stringv.stringv,s,chunksize);
chars->value.stringv.stringv[chunksize] = '\0';
s += chunksize;
}
/* Do last chunk */
chars->nctype = NC_STRING;
chars->lineno = lineno;
chars->value.stringv.len = strlen(s);
chars->value.stringv.stringv = nulldup(s);
}
return charlist;
}
#endif
#ifdef IGNORE
static int
stringexplode(Datasrc* src, size_t chunksize)
{
Constant* con;
Datalist* charlist;
if(!isstring(src)) return 0;
con = srcnext(src);
charlist = dividestringlist(con->value.stringv.stringv,chunksize,srcline(src));
srcpushlist(src,charlist);
return 1;
}
#endif
#ifdef IGNORE
static Datalist*
padstringlist(char* s, size_t chunksize, int lineno)
{
size_t slen;
Datalist* charlist;
Constant* chars;
if(s == NULL) s = "";
slen = strlen(s);
ASSERT(chunksize > 0);
ASSERT(chunksize >= slen);
charlist = builddatalist(1);
if(!charlist) return NULL;
charlist->readonly = 0;
charlist->length = 1;
chars=charlist->data;
chars->nctype = NC_STRING;
chars->lineno = lineno;
chars->value.stringv.len = chunksize;
chars->value.stringv.stringv = emalloc(chunksize+1);
if(chars->value.stringv.stringv == NULL) return NULL;
memset((void*)chars->value.stringv.stringv,0,chunksize+1);
strcpy(chars->value.stringv.stringv,s);
return charlist;
}
#endif
#ifdef IGNORE
static int
stringpad(Datasrc* src, size_t chunksize)
{
Constant* con;
Datalist* charlist;
if(!isstring(src)) return 0;
con = srcnext(src);
charlist = padstringlist(con->value.stringv.stringv,chunksize,srcline(src));
srcpushlist(src,charlist);
return 1;
}
#endif
#ifdef IGNORE
/* Fill */
static int
fillstring(size_t declsize, int len, Bytebuffer* databuf, int fillchar)
{
for(;len<declsize;len++)
/* Following cases should be consistent with isstringable */
size_t constsize = 1;
switch (con->nctype) {
case NC_CHAR:
bbAppend(databuf,con->value.charv);
break;
case NC_BYTE:
bbAppend(databuf,con->value.int8v);
break;
case NC_UBYTE:
bbAppend(databuf,con->value.uint8v);
break;
case NC_STRING:
constsize = con->value.stringv.len;
bbCat(databuf,con->value.stringv.stringv);
bbNull(databuf);
break;
case NC_FILL:
bbAppend(databuf,fillchar);
return len;
break;
default:
PANIC("unexpected constant type");
}
return constsize;
}
#endif
int
static int
getfillchar(Datalist* fillsrc)
{
/* Determine the fill char */
@ -368,102 +203,3 @@ getfillchar(Datalist* fillsrc)
if(fillchar == 0) fillchar = NC_FILL_CHAR; /* default */
return fillchar;
}
/*
Take constant, and if stringable, append to databuf as characters.
If the constant, as a string, is not a multiple in length of dimsize,
then pad using fillchar
*/
int
collectstring(Constant* con, size_t dimsize, Bytebuffer* databuf, int fillchar)
{
size_t padding = 0;
if(dimsize == 0) dimsize = 1;
if(con == NULL) con = &fillconstant;
switch (con->nctype) {
case NC_STRING: {
char* s = con->value.stringv.stringv;
size_t slen = con->value.stringv.len;
padding = (slen % dimsize == 0 ? 0 : dimsize - (slen % dimsize));
if(slen > 0) bbAppendn(databuf,s,slen);
} break;
case NC_FILLVALUE:
padding = dimsize;
break;
case NC_CHAR:
case NC_BYTE:
case NC_UBYTE:
/* Append */
bbAppend(databuf,con->value.charv);
break;
default:
semerror(con->lineno,"Non string or character constant encountered");
return 0;
}
while(padding-- > 0) bbAppend(databuf,fillchar);
bbNull(databuf);
return 1;
}
/* Given a list of stringables (e.g. strings),
make each be a multiple in size of size.
Then concat them all together and create
and return a new Constant containg that string.
*/
int
buildcanonicalcharlist(Datalist* list, size_t size, int fillchar, Constant* conp)
{
int i;
Bytebuffer* buf = bbNew();
Constant* con = NULL;
Constant newcon = nullconstant;
if(list->length == 0) {
/* If an empty list, then produce a string of size size using fillchar*/
for(i=0;i<size;i++) bbAppend(buf,fillchar);
} else for(i=0;i<list->length;i++) {
con = list->data+i;
if(!collectstring(con,size,buf,fillchar)) return 0;
}
bbNull(buf);
/* Construct the new string constant */
newcon.nctype = NC_STRING;
newcon.lineno = (list->length == 0 ? 0: list->data[0].lineno);
newcon.value.stringv.len = bbLength(buf);
newcon.value.stringv.stringv = bbDup(buf);
bbFree(buf);
if(conp) *conp = newcon;
return 1;
}
void
padstring(Constant* con, size_t desiredlength, int fillchar)
{
size_t len = con->value.stringv.len;
char* s = con->value.stringv.stringv;
ASSERT(con->nctype == NC_STRING);
if(len > desiredlength) {
semerror(con->lineno,"String constant too long");
con->value.stringv.len = desiredlength;
} else if(len < desiredlength) {
s = realloc(s,desiredlength+1);
memset(s+len,fillchar,(desiredlength - len));
s[desiredlength] = '\0';
con->value.stringv.stringv = s;
con->value.stringv.len = desiredlength;
}
}
#ifdef IGNORE
static size_t
padround(size_t udimsize, Constant* con)
{
size_t r;
ASSERT(con->nctype == NC_STRING);
r = (con->value.stringv.len + (udimsize-1))/udimsize;
r = r * udimsize;
return r;
}
#endif

390
ncgen/generate.c Normal file
View File

@ -0,0 +1,390 @@
/*********************************************************************
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
#include "includes.h"
#include "nciter.h"
#include "odom.h"
#include "offsets.h"
/**************************************************/
/* Code for generating data lists*/
/**************************************************/
/* For datalist constant rules: see the rules on the man page */
/* Forward*/
static void generate_array(Symbol*,Bytebuffer*,Datalist*,Generator*,Writer);
static void generate_arrayr(Symbol*,Bytebuffer*,Datalist*,Odometer*,int,Datalist*,Generator*);
static void generate_primdata(Symbol*, Constant*, Bytebuffer*, Datalist* fillsrc, Generator*);
static void generate_fieldarray(Symbol*, Constant*, Dimset*, Bytebuffer*, Datalist* fillsrc, Generator*);
/* Mnemonics */
#define VLENLIST1
#define FIELDARRAY 1
/**************************************************/
/* Generator general procedures */
int
generator_getstate(Generator* generator ,void** statep)
{
if(statep) *statep = (void*)generator->state;
return 1;
}
int generator_reset(Generator* generator, void* state)
{
generator->state = state;
return 1;
}
/**************************************************/
void
generate_attrdata(Symbol* asym, Generator* generator, Writer writer, Bytebuffer* codebuf)
{
Symbol* basetype = asym->typ.basetype;
nc_type typecode = basetype->typ.typecode;
if(typecode == NC_CHAR) {
gen_charattr(asym->data,codebuf);
} else {
int uid;
size_t count;
generator->listbegin(generator,LISTATTR,asym->data->length,codebuf,&uid);
for(count=0;count<asym->data->length;count++) {
Constant* con = datalistith(asym->data,count);
generator->list(generator,LISTATTR,uid,count,codebuf);
generate_basetype(asym->typ.basetype,con,codebuf,NULL,generator);
}
generator->listend(generator,LISTATTR,uid,count,codebuf);
}
writer(generator,asym,codebuf,0,NULL,NULL);
}
void
generate_vardata(Symbol* vsym, Generator* generator, Writer writer, Bytebuffer* code)
{
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
Symbol* basetype = vsym->typ.basetype;
Datalist* filler = getfiller(vsym);
if(vsym->data == NULL) return;
/* give the buffer a running start to be large enough*/
bbSetalloc(code, nciterbuffersize);
if(rank == 0) {/*scalar case*/
Constant* c0 = datalistith(vsym->data,0);
generate_basetype(basetype,c0,code,filler,generator);
writer(generator,vsym,code,0,NULL,NULL);
} else {/*rank > 0*/
generate_array(vsym,code,filler,generator,writer);
}
}
static void
generate_array(Symbol* vsym,
Bytebuffer* code,
Datalist* filler,
Generator* generator,
Writer writer
)
{
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
Symbol* basetype = vsym->typ.basetype;
nc_type typecode = basetype->typ.typecode;
Odometer* odom;
nciter_t iter;
ASSERT(rank > 0);
/* Start by doing the two easy cases */
if(typecode == NC_CHAR) { /* case 1: character typed variable, rank > 0 */
Bytebuffer* charbuf = bbNew();
odom = newodometer(dimset,NULL,NULL);
gen_chararray(dimset,vsym->data,charbuf,filler);
generator->charconstant(generator,code,charbuf);
bbFree(charbuf);
writer(generator,vsym,code,odom->rank,odom->start,odom->count);
} else
/* Case 2: the only unlimited is dimension 0 */
if(findunlimited(dimset,1) == rank) {
/* Create an iterator and odometer and just walk the datalist */
nc_get_iter(vsym,nciterbuffersize,&iter);
odom = newodometer(dimset,NULL,NULL);
for(;;) {
int i,uid;
size_t nelems=nc_next_iter(&iter,odom->start,odom->count);
if(nelems == 0) break;
generator->listbegin(generator,LISTDATA,vsym->data->length,code,&uid);
for(i=0;i<nelems;i++) {
Constant* con = datalistith(vsym->data,i);
generator->list(generator,LISTDATA,uid,i,code);
generate_basetype(basetype,con,code,filler,generator);
}
generator->listend(generator,LISTDATA,uid,i,code);
writer(generator,vsym,code,rank,odom->start,odom->count);
}
} else
{ /* Hard case: multiple unlimited dimensions */
/* Setup iterator and odometer */
nc_get_iter(vsym,nciterbuffersize,&iter);
odom = newodometer(dimset,NULL,NULL);
for(;;) {/* iterate in nelem chunks */
/* get nelems count and modify odometer */
size_t nelems=nc_next_iter(&iter,odom->start,odom->count);
if(nelems == 0) break;
generate_arrayr(vsym,code,vsym->data,
odom,
/*dim index=*/0,
filler,generator
);
writer(generator,vsym,code,odom->rank,odom->start,odom->count);
}
}
odometerfree(odom);
}
static void
generate_arrayr(Symbol* vsym,
Bytebuffer* code,
Datalist* list,
Odometer* odom,
int dimindex,
Datalist* filler,
Generator* generator
)
{
Symbol* basetype = vsym->typ.basetype;
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
int lastunlimited;
lastunlimited = findlastunlimited(dimset);
if(lastunlimited == rank) lastunlimited = 0;
ASSERT(rank > 0);
ASSERT(dimindex >= 0 && dimindex < rank);
ASSERT(basetype->typ.typecode != NC_CHAR);
if(dimindex == lastunlimited) {
int uid,i;
Odometer* slabodom;
/* build a special odometer to walk the last few dimensions
(similar to case 2 above)
*/
slabodom = newsubodometer(odom,dimset,dimindex,rank);
/* compute the starting offset in our datalist
(Assumes that slabodom->index[i] == slabodom->start[i])
*/
generator->listbegin(generator,LISTDATA,list->length,code,&uid);
for(i=0;odometermore(slabodom);i++) {
size_t offset = odometeroffset(slabodom);
Constant* con = datalistith(list,offset);
generator->list(generator,LISTDATA,uid,i,code);
generate_basetype(basetype,con,code,filler,generator);
odometerincr(slabodom);
}
generator->listend(generator,LISTDATA,uid,i,code);
odometerfree(slabodom);
} else {
/* If we are strictly to the left of the next unlimited
then our datalist is a list of compounds representing
the next unlimited; so walk the subarray from this index
upto next unlimited.
*/
int i;
Odometer* slabodom;
int nextunlimited = findunlimited(dimset,dimindex+1);
ASSERT((dimindex < lastunlimited
&& (dimset->dimsyms[dimindex]->dim.isunlimited)));
/* build a sub odometer */
slabodom = newsubodometer(odom,dimset,dimindex,nextunlimited);
/* compute the starting offset in our datalist
(Assumes that slabodom->index[i] == slabodom->start[i])
*/
for(i=0;odometermore(slabodom);i++) {
size_t offset = odometeroffset(slabodom);
Constant* con = datalistith(list,offset);
if(!islistconst(con))
semwarn(constline(con),"Expected {...} representing unlimited list");
else {
Datalist* sublist = con->value.compoundv;
generate_arrayr(vsym,code,sublist,odom,nextunlimited,filler,generator);
}
odometerincr(slabodom);
}
odometerfree(slabodom);
}
return;
}
/* Generate an instance of the basetype */
void
generate_basetype(Symbol* tsym, Constant* con, Bytebuffer* codebuf, Datalist* filler, Generator* generator)
{
Datalist* data;
switch (tsym->subclass) {
case NC_ENUM:
case NC_OPAQUE:
case NC_PRIM:
if(islistconst(con)) {
semerror(constline(con),"Expected primitive found {..}");
}
generate_primdata(tsym,con,codebuf,filler,generator);
break;
case NC_COMPOUND: {
int i,uid;
if(con == NULL || isfillconst(con)) {
Datalist* fill = (filler==NULL?getfiller(tsym):filler);
ASSERT(fill->length == 1);
con = &fill->data[0];
if(!islistconst(con))
semerror(con->lineno,"Compound data fill value is not enclosed in {..}");
}
if(!islistconst(con)) {/* fail on no compound*/
semerror(constline(con),"Compound data must be enclosed in {..}");
}
data = con->value.compoundv;
generator->listbegin(generator,LISTCOMPOUND,listlength(tsym->subnodes),codebuf,&uid);
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
con = datalistith(data,i);
generator->list(generator,LISTCOMPOUND,uid,i,codebuf);
generate_basetype(field,con,codebuf,NULL,generator);
}
generator->listend(generator,LISTCOMPOUND,uid,i,codebuf);
} break;
case NC_VLEN: {
Bytebuffer* vlenbuf;
int uid;
size_t count;
if(con == NULL || isfillconst(con)) {
Datalist* fill = (filler==NULL?getfiller(tsym):filler);
ASSERT(fill->length == 1);
con = &fill->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Vlen data fill value is not enclosed in {..}");
}
}
if(!islistconst(con)) {
semerror(constline(con),"Vlen data must be enclosed in {..}");
}
data = con->value.compoundv;
/* generate the nc_vlen_t instance*/
vlenbuf = bbNew();
if(tsym->typ.basetype->typ.typecode == NC_CHAR) {
gen_charvlen(data,vlenbuf);
generator->vlenstring(generator,vlenbuf,&uid,&count);
} else {
generator->listbegin(generator,LISTVLEN,data->length,codebuf,&uid);
for(count=0;count<data->length;count++) {
generator->list(generator,LISTVLEN,uid,count,vlenbuf);
generate_basetype(tsym->typ.basetype,datalistith(data,count),vlenbuf,NULL,generator);
}
generator->listend(generator,LISTVLEN,uid,count,codebuf,(void*)vlenbuf);
}
generator->vlendecl(generator,codebuf,tsym,uid,count,vlenbuf);
bbFree(vlenbuf);
} break;
case NC_FIELD:
if(tsym->typ.dimset.ndims > 0) {
/* Verify that we have a sublist (or fill situation) */
if(con != NULL && !isfillconst(con) && !islistconst(con))
semerror(constline(con),"Dimensioned fields must be enclose in {...}");
generate_fieldarray(tsym->typ.basetype,con,&tsym->typ.dimset,codebuf,filler,generator);
} else {
generate_basetype(tsym->typ.basetype,con,codebuf,NULL,generator);
}
break;
default: PANIC1("generate_basetype: unexpected subclass %d",tsym->subclass);
}
}
/* Used only for structure field arrays*/
static void
generate_fieldarray(Symbol* basetype, Constant* con, Dimset* dimset,
Bytebuffer* codebuf, Datalist* filler, Generator* generator)
{
int i;
int chartype = (basetype->typ.typecode == NC_CHAR);
Datalist* data;
ASSERT(dimset->ndims > 0);
if(con != NULL && !isfillconst(con))
data = con->value.compoundv;
else
data = NULL;
if(chartype) {
/* Collect the char field in a separate buffer */
Bytebuffer* charbuf = bbNew();
gen_chararray(dimset,data,charbuf,filler);
generator->charconstant(generator,codebuf,charbuf);
bbFree(charbuf);
} else {
int uid;
size_t xproduct = crossproduct(dimset,0,0); /* compute total number of elements */
generator->listbegin(generator,LISTFIELDARRAY,xproduct,codebuf,&uid);
for(i=0;i<xproduct;i++) {
con = (data == NULL ? NULL : datalistith(data,i));
generator->list(generator,LISTFIELDARRAY,uid,i,codebuf);
generate_basetype(basetype,con,codebuf,NULL,generator);
}
generator->listend(generator,LISTFIELDARRAY,uid,i,codebuf);
}
}
static void
generate_primdata(Symbol* basetype, Constant* prim, Bytebuffer* codebuf,
Datalist* filler, Generator* generator)
{
Constant target;
if(prim == NULL || isfillconst(prim)) {
Datalist* fill = (filler==NULL?getfiller(basetype):filler);
ASSERT(fill->length == 1);
prim = datalistith(fill,0);
}
ASSERT(prim->nctype != NC_COMPOUND);
target.nctype = basetype->typ.typecode;
if(target.nctype != NC_ECONST) {
convert1(prim,&target);
}
switch (target.nctype) {
case NC_ECONST:
if(basetype->subclass != NC_ENUM) {
semerror(constline(prim),"Conversion to enum not supported (yet)");
} break;
case NC_OPAQUE:
setprimlength(&target,basetype->typ.size*2);
break;
default:
break;
}
generator->constant(generator,&target,codebuf);
return;
}

View File

@ -64,11 +64,41 @@ verror(fmt,va_alist) const char* fmt; va_dcl
vderror(newfmt,argv);
}
#ifndef NO_STDARG
void
semwarn(const int lno, const char *fmt, ...)
#else
void
semwarn(lno,fmt,va_alist) const int lno; const char* fmt; va_dcl
#endif
{
va_list argv;
vastart(argv,fmt);
(void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lno);
vderror(fmt,argv);
}
#ifndef NO_STDARG
void
semerror(const int lno, const char *fmt, ...)
#else
void
semerror(lno,fmt,va_alist) const int lno; const char* fmt; va_dcl
#endif
{
va_list argv;
vastart(argv,fmt);
(void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lno);
vderror(fmt,argv);
exit(1);
}
/* Capture potential version errors */
static char* markcdf4_msg = NULL;
void
markcdf4(const char* msg)
{
enhanced_flag = 1;
if(markcdf4_msg == NULL)
markcdf4_msg = (char*)msg;
}

View File

@ -14,7 +14,7 @@
/*MNEMONIC*/
#define USEMEMORY 1
extern List* vlenconstants; /* List<Constant*>;*/
static List* f77procs = NULL; /* bodies of generated procedures */
/* Forward */
static void genf77_definevardata(Symbol* vsym);
@ -31,13 +31,15 @@ static const char* nfstype(nc_type nctype);
static const char* ncftype(nc_type type);
static const char* nfdtype(nc_type type);
static void f77skip(void);
static void f77comment(char* cmt);
static void f77fold(Bytebuffer* lines);
static void f77flush(void);
static void genf77_write(Symbol*, Bytebuffer*, Odometer*, int, int);
static void genf77_write(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static void genf77_writevar(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static void genf77_writeattr(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
#ifdef USE_NETCDF4
static char* f77prefixed(List* prefix, char* suffix, char* separator);
@ -313,6 +315,7 @@ gen_ncf77(const char *filename)
f77comment("leave define mode");
codeline("stat = nf_enddef(ncid);");
codeline("call check_err(stat)");
f77skip();
f77flush();
/* Assign scalar variable data and non-unlimited arrays in-line */
@ -331,18 +334,26 @@ gen_ncf77(const char *filename)
/* Invoke write procedures */
if(nvars > 0) {
List* calllist;
f77skip();
f77skip();
f77comment("perform variable data writes");
for(ivar = 0; ivar < nvars; ivar++) {
int i;
Symbol* vsym = (Symbol*)listget(vardefs,ivar);
/* Call the procedures for writing unlimited variables */
if(vsym->data != NULL
&& vsym->typ.dimset.ndims > 0) {
bbprintf0(stmt,"call write_%s(ncid,%s_id)\n",
f77name(vsym),f77name(vsym));
codedump(stmt);
genf77_definevardata(vsym);
}
/* dump any calls */
generator_getstate(f77_generator,(void*)&calllist);
ASSERT(calllist != NULL);
for(i=0;i<listlength(calllist);i++) {
char* callstmt = (char*)listget(calllist,i);
codeline(callstmt);
}
listclear(calllist);
}
}
@ -352,14 +363,15 @@ gen_ncf77(const char *filename)
codeline("end");
/* Generate the write procedures */
if(nvars > 0) {
if(listlength(f77procs) > 0) {
int i;
f77skip();
for(ivar = 0; ivar < nvars; ivar++) {
Symbol* vsym = (Symbol*)listget(vardefs,ivar);
if(vsym->data == NULL) continue;
if(vsym->typ.dimset.ndims > 0)
genf77_definevardata(vsym);
for(i=0;i<listlength(f77procs);i++) {
Bytebuffer* proctext = (Bytebuffer*)listget(f77procs,i);
codedump(proctext);
bbFree(proctext);
}
listfree(f77procs); f77procs = NULL;
f77skip();
}
f77flush();
@ -464,63 +476,13 @@ f77name(Symbol* sym)
static void
genf77_defineattr(Symbol* asym)
{
unsigned long len;
Datalist* list;
Symbol* basetype = asym->typ.basetype;
Bytebuffer* code = NULL; /* capture other decls*/
list = asym->data;
len = list==NULL?0:list->length;
bbprintf0(stmt,"* define %s\n",asym->name);
codedump(stmt);
code = bbNew();
f77data_attrdata(asym,code);
/* Use the specialized put_att_XX routines if possible*/
switch (basetype->typ.typecode) {
case NC_BYTE:
case NC_SHORT:
case NC_INT:
case NC_FLOAT:
case NC_DOUBLE:
f77attrify(asym,code);
codedump(code);
bbClear(code);
bbprintf0(stmt,"stat = nf_put_att_%s(ncid, %s, %s, %s, %lu, %sval)\n",
nfstype(basetype->typ.typecode),
(asym->att.var == NULL?"NF_GLOBAL"
:f77varncid(asym->att.var)),
f77escapifyname(asym->name),
nftype(basetype->typ.typecode),
len,
ncftype(basetype->typ.typecode));
codedump(stmt);
break;
case NC_CHAR:
len = bbLength(code);
f77quotestring(code);
if(len==0) len++;
bbprintf0(stmt,"stat = nf_put_att_text(ncid, %s, %s, %lu, ",
(asym->att.var == NULL?"NF_GLOBAL"
:f77varncid(asym->att.var)),
f77escapifyname(asym->name),
len);
codedump(stmt);
codedump(code);
codeline(")");
break;
default: /* User defined type */
verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
break;
}
Bytebuffer* code = bbNew();
List* oldstate = NULL;
generator_getstate(f77_generator,(void*)&oldstate);
listfree(oldstate);
generator_reset(f77_generator,(void*)listnew());
generate_attrdata(asym,f77_generator,(Writer)genf77_write,code);
bbFree(code);
codeline("call check_err(stat)");
}
static void
@ -756,91 +718,80 @@ ncftype(nc_type type)
static void
genf77_definevardata(Symbol* vsym)
{
Dimset* dimset = &vsym->typ.dimset;
int isscalar = (dimset->ndims == 0);
Bytebuffer* code = NULL;
Datasrc* src = NULL;
Datalist* fillsrc = NULL;
nciter_t iter;
Odometer* odom = NULL;
size_t nelems;
int chartype = (vsym->typ.basetype->typ.typecode == NC_CHAR);
if(vsym->data == NULL) return;
src = datalist2src(vsym->data);
code = bbNew();
/* give the buffer a running start to be large enough*/
bbSetalloc(code, nciterbuffersize);
if(!isscalar && chartype) {
gen_chararray(vsym,src,code,fillsrc);
genf77_write(vsym,code,NULL,0,0);
} else { /* not character constant */
fillsrc = vsym->var.special._Fillvalue;
/* Handle special cases first*/
if(isscalar) {
f77data_basetype(vsym->typ.basetype,src,code,fillsrc);
commify(code);
genf77_write(vsym,code,NULL,1,0);
} else { /* Non-scalar*/
int index;
/* 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(index=0;;index++) {
nelems=nc_next_iter(&iter,odom->start,odom->count);
if(nelems == 0) break;
f77data_array(vsym,code,src,odom,/*index=*/0,fillsrc);
genf77_write(vsym,code,odom,0,index);
}
}
odometerfree(odom);
}
Bytebuffer* code = bbNew();
List* oldstate = NULL;
generator_getstate(f77_generator,(void*)&oldstate);
listfree(oldstate);
generator_reset(f77_generator,(void*)listnew());
generate_vardata(vsym,f77_generator,(Writer)genf77_write,code);
bbFree(code);
}
static void
genf77_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar,
int index)
genf77_write(Generator* generator, Symbol* sym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
if(sym->objectclass == NC_ATT)
genf77_writeattr(generator,sym,code,rank,start,count);
else if(sym->objectclass == NC_VAR) {
genf77_writevar(generator,sym,code,rank,start,count);
}
else
PANIC("illegal symbol for genf77_write");
}
static void
genf77_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
int typecode = vsym->typ.basetype->typ.typecode;
int chartype = (typecode == NC_CHAR);
int i;
if(isscalar) {
if(chartype) {
bbprintf0(stmt,"stat = nf_put_var_%s(ncid, %s, %s)\n",
/* Deal with character variables specially */
if(typecode == NC_CHAR) {
f77quotestring(code);
bbprintf0(stmt,"stat = nf_put_var_%s(ncid, %s, %s)\n",
nfstype(typecode),
f77varncid(vsym),
bbContents(code));
codedump(stmt);
} else {
bbprintf0(stmt,"data %s /%s/\n",
codedump(stmt);
codeline("call check_err(stat)");
f77skip();
} else if(rank == 0) {
commify(code); /* insert commas as needed */
bbprintf0(stmt,"data %s /%s/\n",
f77name(vsym),bbContents(code));
codedump(stmt);
bbprintf0(stmt,"stat = nf_put_var_%s(ncid, %s, %s)\n",
codedump(stmt);
bbprintf0(stmt,"stat = nf_put_var_%s(ncid, %s, %s)\n",
nfstype(typecode),
f77varncid(vsym),
f77name(vsym));
codedump(stmt);
}
codedump(stmt);
codeline("call check_err(stat)");
f77skip();
} else { /* array */
} else { /* rank > 0 && typecode != NC_CHAR*/
char* dimstring;
int index = listlength(f77procs);
Bytebuffer* proctext;
Bytebuffer* save;
List* calllist;
/* Construct the procedure body */
f77skip();
if(index == 0)
bbprintf0(stmt,"subroutine write_%s(ncid,%s_id)\n",
f77name(vsym),f77name(vsym));
else
bbprintf0(stmt,"subroutine write_%s_%d(ncid,%s_id)\n",
f77name(vsym),f77name(vsym),index);
/* Generate the call to the procedure */
bbprintf0(stmt,"call write_%s_%d(ncid,%s_id_%d)\n",
f77name(vsym),index,f77name(vsym));
/* save in the generator state */
generator_getstate(generator,(void*)&calllist);
ASSERT(calllist != NULL);
listpush(calllist,(elem_t)bbDup(stmt));
/* Construct the procedure body and save it */
proctext = bbNew();
save = codebuffer;
codebuffer = proctext;
f77skip();
bbprintf0(stmt,"subroutine write_%s_%d(ncid,%s_id)\n",
f77name(vsym),index,f77name(vsym));
codedump(stmt);
codeline("integer ncid");
bbprintf0(stmt,"integer %s_id\n",f77name(vsym));
@ -856,69 +807,129 @@ genf77_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar,
codedump(stmt);
f77skip();
if(typecode != NC_CHAR) {
/* Compute the dimensions (in reverse order for fortran) */
bbClear(stmt);
for(i=rank-1;i>=0;i--) {
char tmp[32];
nprintf(tmp,sizeof(tmp),"%s%lu",
/* Compute the dimensions (in reverse order for fortran) */
bbClear(stmt);
for(i=rank-1;i>=0;i--) {
char tmp[32];
nprintf(tmp,sizeof(tmp),"%s%lu",
(i==(rank-1)?"":","),
odom->count[i]);
bbCat(stmt,tmp);
}
dimstring = bbDup(stmt);
commify(code);
bbprintf0(stmt,"%s %s(%s)\n",
count[i]);
bbCat(stmt,tmp);
}
dimstring = bbDup(stmt);
commify(code);
bbprintf0(stmt,"%s %s(%s)\n",
nfdtype(typecode),
f77name(vsym),
dimstring);
efree(dimstring);
codedump(stmt);
/* Generate the data // statement */
bbprintf0(stmt,"data %s /",f77name(vsym));
bbCatbuf(stmt,code);
bbCat(stmt,"/\n");
codedump(stmt);
}
/* Set the values for the start and count sets
but in reverse order
*/
for(i=0;i<dimset->ndims;i++) {
int reverse = (dimset->ndims - i) - 1;
bbprintf0(stmt,"%s_start(%d) = %lu\n",
f77name(vsym),
i+1,
odom->start[reverse]+1); /* +1 for FORTRAN */
codedump(stmt);
}
for(i=0;i<dimset->ndims;i++) {
int reverse = (dimset->ndims - i) - 1;
bbprintf0(stmt,"%s_count(%d) = %lu\n",
f77name(vsym),
i+1,
odom->count[reverse]);
codedump(stmt);
}
bbprintf0(stmt,"stat = nf_put_vara_%s(ncid, %s, %s_start, %s_count, ",
nfstype(typecode),
f77varncid(vsym),
f77name(vsym),
f77name(vsym));
efree(dimstring);
codedump(stmt);
if(typecode == NC_CHAR) {
f77quotestring(code);
codedump(code);
} else {
codeprintf("%s",f77name(vsym));
}
codeline(")");
codeline("call check_err(stat)");
/* Close off the procedure */
codeline("end");
/* Generate the data // statement */
commify(code); /* insert commas as needed */
bbprintf0(stmt,"data %s /",f77name(vsym));
bbCatbuf(stmt,code);
bbCat(stmt,"/\n");
codedump(stmt);
/* Set the values for the start and count sets
but in reverse order
*/
for(i=0;i<dimset->ndims;i++) {
int reverse = (dimset->ndims - i) - 1;
bbprintf0(stmt,"%s_start(%d) = %lu\n",
f77name(vsym),
i+1,
start[reverse]+1); /* +1 for FORTRAN */
codedump(stmt);
}
for(i=0;i<dimset->ndims;i++) {
int reverse = (dimset->ndims - i) - 1;
bbprintf0(stmt,"%s_count(%d) = %lu\n",
f77name(vsym),
i+1,
count[reverse]);
codedump(stmt);
}
bbprintf0(stmt,"stat = nf_put_vara_%s(ncid, %s, %s_start, %s_count, ",
nfstype(typecode),
f77varncid(vsym),
f77name(vsym),
f77name(vsym));
codedump(stmt);
if(typecode == NC_CHAR) {
f77quotestring(code);
codedump(code);
} else {
codeprintf("%s",f77name(vsym));
}
codeline(")");
codeline("call check_err(stat)");
/* Close off the procedure */
codeline("end");
/* save the generated procedure(s) */
if(f77procs == NULL) f77procs = listnew();
listpush(f77procs,(elem_t)codebuffer);
codebuffer = save;
}
}
static void
genf77_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Datalist* list;
Symbol* basetype = asym->typ.basetype;
size_t len = asym->data->length; /* default assumption */
list = asym->data;
len = list==NULL?0:list->length;
bbprintf0(stmt,"* define %s\n",asym->name);
codedump(stmt);
/* Use the specialized put_att_XX routines if possible*/
switch (basetype->typ.typecode) {
case NC_BYTE:
case NC_SHORT:
case NC_INT:
case NC_FLOAT:
case NC_DOUBLE:
f77attrify(asym,code);
codedump(code);
bbClear(code);
bbprintf0(stmt,"stat = nf_put_att_%s(ncid, %s, %s, %s, %lu, %sval)\n",
nfstype(basetype->typ.typecode),
(asym->att.var == NULL?"NF_GLOBAL"
:f77varncid(asym->att.var)),
f77escapifyname(asym->name),
nftype(basetype->typ.typecode),
len,
ncftype(basetype->typ.typecode));
codedump(stmt);
break;
case NC_CHAR:
len = bbLength(code);
f77quotestring(code);
if(len==0) len++;
bbprintf0(stmt,"stat = nf_put_att_text(ncid, %s, %s, %lu, ",
(asym->att.var == NULL?"NF_GLOBAL"
:f77varncid(asym->att.var)),
f77escapifyname(asym->name),
len);
codedump(stmt);
codedump(code);
codeline(")");
break;
default: /* User defined type */
verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
break;
}
codeline("call check_err(stat)");
}
#endif /*ENABLE_F77*/

View File

@ -21,18 +21,18 @@ extern List* vlenconstants; /* List<Constant*>;*/
/* Forward */
static void genj_definevardata(Symbol* vsym);
static void genj_defineattribute(Symbol* asym);
static void genj_definevardata(Symbol*);
static void genj_write(Symbol*, Bytebuffer*, Odometer*, int, int);
static const char* jtypeallcaps(nc_type type);
static const char* jtypecap(nc_type type);
static const char* jtype(nc_type type);
static const char* jarraytype(nc_type type);
static const char* jname(Symbol* sym);
static void computemaxunlimited(void);
static void genj_defineattr(Symbol* asym);
static void genj_definevardata(Symbol*);
static void genj_write(Generator*,Symbol* sym, Bytebuffer* code,
int rank, size_t* start, size_t* count);
static void genj_writevar(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
static void genj_writeattr(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
/*
* Generate code for creating netCDF from in-memory structure.
@ -174,7 +174,7 @@ gen_ncjava(const char *filename)
codelined(1,"/* assign global attributes */");
for(iatt = 0; iatt < ngatts; iatt++) {
Symbol* gasym = (Symbol*)listget(gattdefs,iatt);
genj_defineattribute(gasym);
genj_defineattr(gasym);
}
codeline("");
codeflush();
@ -186,7 +186,7 @@ gen_ncjava(const char *filename)
codelined(1,"/* assign per-variable attributes */");
for(iatt = 0; iatt < natts; iatt++) {
Symbol* asym = (Symbol*)listget(attdefs,iatt);
genj_defineattribute(asym);
genj_defineattr(asym);
}
codeline("");
codeflush();
@ -204,8 +204,6 @@ gen_ncjava(const char *filename)
if(vsym->data != NULL) genj_definevardata(vsym);
}
codeline("");
/* compute the max actual size of the unlimited dimension*/
if(usingclassic) computemaxunlimited();
}
codeflush();
@ -224,130 +222,6 @@ cl_java(void)
codeflush();
}
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;i<listlength(vardefs);i++) {
Symbol* dim;
Symbol* var = (Symbol*)listget(vardefs,i);
if(var->typ.dimset.ndims == 0) continue; /* rank == 0*/
dim = var->typ.dimset.dimsyms[0];
if(dim->dim.declsize != NC_UNLIMITED) continue; /* var does not use unlimited*/
if(var->typ.dimset.dimsyms[0]->dim.declsize > maxsize)
maxsize = var->typ.dimset.dimsyms[0]->dim.declsize;
}
}
/*
* Return java type name for netCDF type, given type code.
*/
static void
genj_defineattribute(Symbol* asym)
{
unsigned long len;
Symbol* basetype = asym->typ.basetype;
Datalist* list;
Bytebuffer* code = NULL; /* capture other decls*/
nc_type typecode = basetype->typ.typecode;
list = asym->data;
len = list == NULL?0:list->length;
codeprintf("%s/* attribute: %s */\n",indented(1),asym->name);
code = bbNew();
if(typecode == NC_CHAR) {
gen_charattr(asym,code);
} else {
Datasrc* src = datalist2src(asym->data);
while(srcmore(src)) {
jdata_basetype(asym->typ.basetype,src,code,NULL);
}
}
/* Handle NC_CHAR specially */
if(typecode == NC_CHAR) {
/* revise the length count */
len = bbLength(code);
if(len == 0) {
bbAppend(code,'\0'); len++;
bbClear(code);
bbCat(code,"\"\"");
len++;
} else
jquotestring(code,'"');
bbNull(code);
} else {
char* code2;
commify(code);
/* Convert to constant */
code2 = bbDup(code);
bbClear(code);
bbprintf0(stmt,"new %s[]",
jarraytype(typecode));
bbCatbuf(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:
codelined(1,"{");
bbprintf0(stmt,"%sArray data = Array.factory(%s.class, new int[]{%lu}, ",
indented(1),
jtype(basetype->typ.typecode),
len);
codedump(stmt);
codedump(code);
codeline(");");
if(asym->att.var == NULL) {
bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",data);\n",
indented(1),jescapifyname(asym->name));
} else {
bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",data);\n",
indented(1),
jescapifyname(asym->att.var->name),
jescapifyname(asym->name));
}
codedump(stmt);
codelined(1,"}");
codeflush();
break;
case NC_CHAR:
if(asym->att.var == NULL) {
bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",%s);\n",
indented(1),
jescapifyname(asym->name),
bbContents(code));
} else {
bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",%s);\n",
indented(1),
jescapifyname(asym->att.var->name),
jescapifyname(asym->name),
bbContents(code));
}
codedump(stmt);
codeflush();
break;
default: break;
}
}
const char*
jtypeallcaps(nc_type type)
{
@ -539,84 +413,66 @@ jstype(nc_type nctype)
}
}
static void
genj_defineattr(Symbol* asym)
{
Bytebuffer* code; /* capture so we can dump vlens first */
ASSERT(asym->data != NULL);
code = bbNew();
generator_reset(j_generator,NULL);
generate_attrdata(asym,j_generator,(Writer)genj_write,code);
bbFree(code);
}
static void
genj_definevardata(Symbol* vsym)
{
Dimset* dimset = &vsym->typ.dimset;
int isscalar = (dimset->ndims == 0);
Bytebuffer* code;
Datasrc* src = NULL;
Datalist* fillsrc = NULL;
nciter_t iter;
Odometer* odom = NULL;
size_t nelems;
int chartype = (vsym->typ.basetype->typ.typecode == NC_CHAR);
Bytebuffer* code; /* capture so we can dump vlens first */
if(vsym->data == NULL) return;
src = datalist2src(vsym->data);
code = bbNew();
/* give the buffer a running start to be large enough*/
bbSetalloc(code, nciterbuffersize);
if(!isscalar && chartype) {
gen_chararray(vsym,src,code,fillsrc);
genj_write(vsym,code,NULL,0,0);
} else { /* not character constant */
fillsrc = vsym->var.special._Fillvalue;
/* Handle special cases first*/
if(isscalar) {
jdata_basetype(vsym->typ.basetype,src,code,fillsrc);
commify(code);
genj_write(vsym,code,NULL,1,0);
} else { /* Non-scalar*/
int index;
/* 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(index=0;;index++) {
nelems=nc_next_iter(&iter,odom->start,odom->count);
if(nelems == 0) break;
jdata_array(vsym,code,src,odom,/*index=*/0,fillsrc);
genj_write(vsym,code,odom,0,index);
}
}
odometerfree(odom);
}
generator_reset(j_generator,NULL);
generate_vardata(vsym,j_generator,(Writer)genj_write,code);
bbFree(code);
}
static void
genj_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar, int index)
genj_write(Generator* generator, Symbol* sym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
if(sym->objectclass == NC_ATT)
genj_writeattr(generator,sym,code,rank,start,count);
else if(sym->objectclass == NC_VAR)
genj_writevar(generator,sym,code,rank,start,count);
else
PANIC("illegal symbol for genj_write");
}
static void
genj_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
int typecode = vsym->typ.basetype->typ.typecode;
int chartype = (typecode == NC_CHAR);
int i;
codeline("");
codelined(1,"{"); /* Enclose in {...} for scoping */
if(isscalar) {
/* Construct the data Array */
if(rank == 0) {
bbprintf0(stmt,"%sArray%s.D0 data = new Array%s.D0();\n",
indented(1),jtypecap(typecode), jtypecap(typecode));
codedump(stmt);
if(chartype) {
#ifdef IGNORE
jquotestring(code,'"');
bbprintf0(stmt,"%sdata.set(%s.charAt(0));\n",
indented(1),bbContents(code));
#else
bbprintf0(stmt,"%sdata.set((char)%s);\n",
indented(1),bbContents(code));
#endif
if(typecode == NC_CHAR) {
/* Construct the data Array */
jquotestring(code,'\'');
bbprintf0(stmt,"%sdata.set((char)%s);\n",
indented(1),bbContents(code));
} else {
commify(code);
bbprintf0(stmt,"%sdata.set((%s)%s);\n",
indented(1),jtype(typecode),bbContents(code));
}
indented(1),jtype(typecode),bbContents(code));
}
codedump(stmt);
/* do the actual write */
bbprintf0(stmt,"%sncfile.write(\"%s\",data);\n",
@ -629,10 +485,7 @@ genj_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar, int ind
for(i=0;i<rank;i++) {
Symbol* dsym = dimset->dimsyms[i];
char tmp[32];
if(i==0 && dsym->dim.declsize == NC_UNLIMITED)
nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.unlimitedsize);
else
nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.declsize);
nprintf(tmp,sizeof(tmp),"%lu",dsym->dim.declsize);
if(i>0) {bbCat(dimbuf,", ");}
bbCat(dimbuf,tmp);
}
@ -668,10 +521,10 @@ genj_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar, int ind
indented(2),jtypecap(typecode));
codedump(stmt);
bbFree(dimbuf);
/* Construct the origin set from the odometer start set */
/* Construct the origin set from the start set */
bbprintf0(stmt,"%sint[] origin = new int[]{",indented(1));
for(i=0;i<rank;i++) {
bbprintf(stmt,"%s%lu",(i>0?", ":""),odom->start[i]);
bbprintf(stmt,"%s%lu",(i>0?", ":""),start[i]);
}
bbCat(stmt,"};\n");
codedump(stmt);
@ -681,5 +534,98 @@ genj_write(Symbol* vsym, Bytebuffer* code, Odometer* odom, int isscalar, int ind
codedump(stmt);
}
codelined(1,"}"); /* Enclose in {...} for scoping */
codeflush();
}
static void
genj_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
int rank, size_t* start, size_t* count)
{
Symbol* basetype = asym->typ.basetype;
nc_type typecode = basetype->typ.typecode;
size_t len = asym->data->length; /* default assumption */
Datalist* list;
list = asym->data;
len = list == NULL?0:list->length;
codeprintf("%s/* attribute: %s */\n",indented(1),asym->name);
/* Handle NC_CHAR specially */
if(typecode == NC_CHAR) {
/* revise the length count */
len = bbLength(code);
if(len == 0) {
bbAppend(code,'\0'); len++;
bbClear(code);
bbCat(code,"\"\"");
len++;
} else
jquotestring(code,'"');
bbNull(code);
} else { /* not NC_CHAR*/
char* code2;
commify(code);
/* Convert to constant */
code2 = bbDup(code);
bbClear(code);
bbprintf0(stmt,"new %s[]",
jarraytype(typecode));
bbCatbuf(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:
codelined(1,"{");
bbprintf0(stmt,"%sArray data = Array.factory(%s.class, new int[]{%lu}, ",
indented(1),
jtype(basetype->typ.typecode),
len);
codedump(stmt);
codedump(code);
codeline(");");
if(asym->att.var == NULL) {
bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",data);\n",
indented(1),jescapifyname(asym->name));
} else {
bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",data);\n",
indented(1),
jescapifyname(asym->att.var->name),
jescapifyname(asym->name));
}
codedump(stmt);
codelined(1,"}");
codeflush();
break;
case NC_CHAR:
if(asym->att.var == NULL) {
bbprintf0(stmt,"%sncfile.addGlobalAttribute(\"%s\",%s);\n",
indented(1),
jescapifyname(asym->name),
bbContents(code));
} else {
bbprintf0(stmt,"%sncfile.addVariableAttribute(\"%s\",\"%s\",%s);\n",
indented(1),
jescapifyname(asym->att.var->name),
jescapifyname(asym->name),
bbContents(code));
}
codedump(stmt);
codeflush();
break;
default: break;
}
codeflush();
}
#endif /*ENABLE_JAVA*/

View File

@ -39,6 +39,7 @@ extern void verror ( const char *fmt, ... )
#endif
;
extern void markcdf4(const char *msg);
extern char* getmarkcdf4(void);
@ -54,13 +55,14 @@ extern void close_netcdf ( void ); /* generates close */
extern char* cprefixed(List* prefix, char* suffix, char* separator);
/* from: escapes.c */
extern void expand_escapes ( char* termstring, char* yytext, int yyleng );
extern void expand_escapes (Bytebuffer* termstring, char* yytext, int yyleng );
extern void deescapify(char *name); /* redunandt over expand_escapes?*/
extern char* decodify(const char *name);
extern char* escapifychar(unsigned int c, char* s0, int quote);
extern char* escapify(char*,int,size_t);
extern char* escapifyname(char* s0);
extern void cquotestring(Bytebuffer*);
extern void cquotestring(Bytebuffer*,char quote);
extern void f77quotestring(Bytebuffer*);
extern char* f77escapifyname(char* s0);
extern char* xescapify(char* s0, int quote, size_t len);
extern char* jescapify(char* s0, int quote, size_t len);
@ -70,8 +72,7 @@ extern char* jdecodify(const char *name);
/* from: getfill.c */
extern void nc_getfill(Constant*);
extern char* nc_dfaltfillname(nc_type);
extern struct Datalist* getfiller(Symbol*,Datalist*); /* type or variable*/
extern int checkfillvalue(Symbol*, struct Datalist*);
extern struct Datalist* getfiller(Symbol*); /* symbol isa variable|type */
/* from: ncgen.y */
extern Symbol* install(const char *sname);
@ -93,32 +94,36 @@ extern Symbol* lookupingroup(nc_class objectclass, char* name, Symbol* grp);
extern Symbol* lookupgroup(List* prefix);
#ifndef NO_STDARG
extern void semerror(const int, const char *fmt, ...);
extern void semwarn(const int, const char *fmt, ...);
#else
extern void semerror(lno,fmt,va_alist) const int lno; const char* fmt; va_dcl;
extern void semwarnlno,fmt,va_alist) const int lno; const char* fmt; va_dcl;
#endif
extern int nounlimited(Dimset* dimset, int from);
extern int lastunlimited(Dimset* dimset);
extern void padstring(Constant* con, size_t desiredlength, int fillchar);
extern Datalist* explodestrings(Datalist*,char*);
extern Datalist* implodestrings(Datalist*,char*);
extern int explodestringconst(Constant* con, char* tag, Constant*);
extern char* indented(int n);
/* Generators for cdf, c, and fortran */
#ifdef ENABLE_BINARY
/* from: genbin.c */
extern Generator* bin_generator;
extern void gen_netcdf(const char *filename);
extern void cl_netcdf(void);
#endif
#ifdef ENABLE_C
/* from: genc.c */
extern Generator* c_generator;
extern void gen_ncc(const char *filename);
extern void cl_c(void);
extern const char* ctypename(Symbol*);
extern char* indented(int n);
extern const char* nctype(nc_type type);
extern const char* ncctype(nc_type type);
extern const char* ncstype(nc_type type);
@ -126,22 +131,16 @@ extern const char* ncstype(nc_type type);
#ifdef ENABLE_F77
/* from: genf77.c */
extern Generator* f77_generator;
extern void gen_ncf77(const char *filename);
extern void cl_f77(void);
extern const char* f77name(Symbol*);
extern const char* f77typename(Symbol*);
#endif
#ifdef ENABLE_CML
/* from: gencml.c */
extern void gen_nccml(const char *filename);
extern void cl_cml(void);
extern char* xname(struct Symbol* sym);
extern char* xtypename(struct Symbol* tsym);
#endif
#ifdef ENABLE_JAVA
/* from: genj.c */
extern Generator* j_generator;
extern void gen_ncjava(const char *filename);
extern void cl_java(void);
extern void jpartial(char*);
@ -150,9 +149,12 @@ extern void jlined(int,char*);
extern void jflush(void);
#endif
/* from: main.c */
extern int usingclassic; /* 0=>false; 1=>true; */
extern int allowspecial;
extern int format_flag; /* _Format attribute value (same range as -k flag) */
extern int enhanced_flag; /* 1 => netcdf-4 constructs appear in the parse */
extern int specials_flag; /* 1 => special attributes are present */
extern int usingclassic; /* 1 => k_flag == 1|2 */
/* Global data */

View File

@ -11,68 +11,58 @@
#define TOPLEVEL 1
/*Forward*/
static Datalist* buildfill(Symbol* tsym);
static void fill(Symbol* tsym, Datalist*);
static void fillarray(Symbol* tsym, Dimset* dimset, int index, Datalist*);
static void filllist(Symbol* tvsym, Datalist* dl);
static int checkfill(Symbol* tvsym, Datasrc* src, Symbol*);
static int checkarray(Symbol* tsym, Dimset* dimset, int index, Datasrc*, Symbol*, int);
/* Construct a Datalist representing a complete fill value*/
/* for a specified type*/
/* for a specified variable */
/* Cache if needed later*/
Datalist*
getfiller(Symbol* tvsym, Datalist* fillsrc)
getfiller(Symbol* tvsym)
{
Datalist* filler = fillsrc;
if(filler == NULL)
Datalist* filler = NULL;
Symbol* tsym = tvsym;
ASSERT(tvsym->objectclass == NC_VAR || tvsym->objectclass == NC_TYPE);
if(tvsym->objectclass == NC_VAR) {
tsym = tvsym->typ.basetype;
filler = tvsym->var.special._Fillvalue; /* get cached value (if any)*/
if(filler == NULL) { /* need to compute it*/
filler = buildfill(tvsym);
tvsym->var.special._Fillvalue = filler; /* cache value*/
}
if(debug >= 1)
if(filler == NULL || tvsym->objectclass == NC_TYPE) {
filler = tvsym->typ._Fillvalue; /* get cached value (if any)*/
}
if(filler == NULL) { /* need to compute it*/
filler = builddatalist(0);
fill(tsym,filler);
}
#ifdef DEBUG2
dumpdatalist(filler,"getfiller");
#endif
if(tvsym->objectclass == NC_VAR) {
tvsym->var.special._Fillvalue = filler;
} else if(tvsym->objectclass == NC_TYPE) {
tvsym->typ._Fillvalue = filler; /* cache value*/
}
return filler;
}
static Datalist*
buildfill(Symbol* tvasym)
{
Datalist* filler = builddatalist(0);
ASSERT(tvasym->objectclass == NC_VAR
|| tvasym->objectclass == NC_TYPE
|| tvasym->objectclass == NC_ATT);
if(tvasym->objectclass == NC_VAR) {
if(tvasym->typ.dimset.ndims > 0) {
fillarray(tvasym->typ.basetype,&tvasym->typ.dimset,0,filler);
} else
fill(tvasym->typ.basetype,filler);
} else if(tvasym->objectclass == NC_ATT) {
fill(tvasym->typ.basetype,filler);
} else /*NC_TYPE*/
fill(tvasym,filler);
return filler;
}
static void
fill(Symbol* tvsym, Datalist* filler)
fill(Symbol* tsym, Datalist* filler)
{
int i;
Constant con;
Datalist* sublist;
/* NC_TYPE case*/
switch (tvsym->subclass) {
ASSERT(tsym->objectclass == NC_TYPE);
switch (tsym->subclass) {
case NC_ENUM: case NC_OPAQUE: case NC_PRIM:
con.nctype = tvsym->typ.typecode;
con.nctype = tsym->typ.typecode;
nc_getfill(&con);
break;
case NC_COMPOUND:
sublist = builddatalist(listlength(tvsym->subnodes));
for(i=0;i<listlength(tvsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tvsym->subnodes,i);
sublist = builddatalist(listlength(tsym->subnodes));
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
if(field->typ.dimset.ndims > 0) {
fillarray(field->typ.basetype,&field->typ.dimset,0,filler);
} else
@ -82,32 +72,32 @@ fill(Symbol* tvsym, Datalist* filler)
break;
case NC_VLEN:
sublist = builddatalist(0);
filllist(tvsym->typ.basetype,sublist); /* generate a single instance*/
filllist(tsym->typ.basetype,sublist); /* generate a single instance*/
con = builddatasublist(sublist);
break;
default: PANIC1("fill: unexpected subclass %d",tvsym->subclass);
default: PANIC1("fill: unexpected subclass %d",tsym->subclass);
}
dlappend(filler,&con);
}
static void
filllist(Symbol* tvsym, Datalist* dl)
filllist(Symbol* tsym, Datalist* dl)
{
int i;
Datalist* sublist;
Constant con;
/* NC_TYPE case*/
switch (tvsym->subclass) {
ASSERT(tsym->objectclass == NC_TYPE);
switch (tsym->subclass) {
case NC_ENUM: case NC_OPAQUE: case NC_PRIM:
con.nctype = tvsym->typ.typecode;
con.nctype = tsym->typ.typecode;
nc_getfill(&con);
dlappend(dl,&con);
break;
case NC_COMPOUND:
sublist = builddatalist(listlength(tvsym->subnodes));
for(i=0;i<listlength(tvsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tvsym->subnodes,i);
sublist = builddatalist(listlength(tsym->subnodes));
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
filllist(field->typ.basetype,sublist);
}
con = builddatasublist(sublist);
@ -115,11 +105,11 @@ filllist(Symbol* tvsym, Datalist* dl)
break;
case NC_VLEN:
sublist = builddatalist(0);
filllist(tvsym->typ.basetype,sublist); /* generate a single instance*/
filllist(tsym->typ.basetype,sublist); /* generate a single instance*/
con = builddatasublist(sublist);
dlappend(dl,&con);
break;
default: PANIC1("fill: unexpected subclass %d",tvsym->subclass);
default: PANIC1("fill: unexpected subclass %d",tsym->subclass);
}
}
@ -153,41 +143,26 @@ fillarray(Symbol* basetype, Dimset* dimset, int index, Datalist* arraylist)
}
}
#ifdef NOTUSED
/* Verify that a user provided fill value does in fact*/
/* conform to the structure of a given type or variable*/
/* Structure conforms to fill procedures above.*/
int
checkfillvalue(Symbol* tvsym, Datalist* filler)
{
Datasrc* src = datalist2src(filler);
int result;
ASSERT(tvsym->objectclass == NC_VAR || tvsym->objectclass == NC_TYPE);
if(tvsym->objectclass == NC_VAR) {
if(tvsym->typ.dimset.ndims > 0) {
result = checkarray(tvsym->typ.basetype,&tvsym->typ.dimset,0,src,tvsym,TOPLEVEL);
} else
result = checkfill(tvsym->typ.basetype,src,tvsym);
} else /* NC_TYPE*/
result = checkfill(tvsym,src,tvsym);
freedatasrc(src);
return result;
}
static int
checkfill(Symbol* tvsym, Datasrc* src, Symbol* original)
checkfill(Symbol* tsym, Datasrc* src)
{
int i,iscmpd,result;
Constant* con;
Symbol* original = tsym;
result = 1;
switch (tvsym->subclass) {
switch (tsym->subclass) {
case NC_ENUM: case NC_OPAQUE: case NC_PRIM:
con = srcnext(src);
if(src == NULL) {
semerror(srcline(src),"%s: malformed _FillValue",original->name);
result = 0;
} else if(con->nctype != tvsym->typ.typecode) result = 0; /* wrong type*/
} else if(con->nctype != tsym->typ.typecode) result = 0; /* wrong type*/
break;
case NC_COMPOUND:
@ -195,8 +170,8 @@ checkfill(Symbol* tvsym, Datasrc* src, Symbol* original)
semerror(srcline(src),"Compound constants must be enclosed in {..}");
}
srcpush(src);
for(i=0;i<listlength(tvsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tvsym->subnodes,i);
for(i=0;i<listlength(tsym->subnodes);i++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
result = checkfill(field,src,original);
if(!result) break;
}
@ -210,7 +185,7 @@ checkfill(Symbol* tvsym, Datasrc* src, Symbol* original)
} else {
srcpush(src);
while(srcmore(src)) {
result = checkfill(tvsym->typ.basetype,src,original);
result = checkfill(tsym->typ.basetype,src,original);
if(!result) break;
}
srcpop(src);
@ -220,14 +195,14 @@ checkfill(Symbol* tvsym, Datasrc* src, Symbol* original)
case NC_FIELD:
/* Braces are optional */
if((iscmpd=issublist(src))) srcpush(src);
if(tvsym->typ.dimset.ndims > 0) {
result = checkarray(tvsym->typ.basetype,&tvsym->typ.dimset,0,src,original,!TOPLEVEL);
if(tsym->typ.dimset.ndims > 0) {
result = checkarray(tsym->typ.basetype,&tsym->typ.dimset,0,src,original,!TOPLEVEL);
} else
result = checkfill(tvsym->typ.basetype,src,original);
result = checkfill(tsym->typ.basetype,src,original);
if(iscmpd) srcpop(src);
break;
default: PANIC1("checkfillvalue: unexpected subclass %d",tvsym->subclass);
default: PANIC1("checkfillvalue: unexpected subclass %d",tsym->subclass);
}
return result;
}
@ -274,6 +249,7 @@ checkarray(Symbol* basetype, Dimset* dimset, int index, Datasrc* src, Symbol* or
done:
return result;
}
#endif /*NOTUSED*/
/*
* Given primitive netCDF type, return a default fill_value appropriate for

View File

@ -39,7 +39,6 @@
#define ENABLE_JAVA
#include "netcdf.h"
#include "odom.h"
#include "data.h"
#include "ncgen.h"
#include "genlib.h"

View File

@ -1,162 +1,155 @@
/*********************************************************************
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
#include "includes.h"
#include "offsets.h"
#include "nciter.h"
#ifdef ENABLE_JAVA
extern List* vlenconstants; /* List<Constant*>;*/
#include <math.h>
/* Forward*/
static void jdata_primdata(Symbol*, Datasrc*, Bytebuffer*, Datalist*);
static int j_uid = 0;
/**************************************************/
/* Code for generating Java language data lists*/
/**************************************************/
/* Datalist rules: see the rules on the man page */
void
jdata_array(Symbol* vsym,
Bytebuffer* databuf,
Datasrc* src,
Odometer* odom,
int index,
Datalist* fillsrc)
static int
j_charconstant(Generator* generator, Bytebuffer* codebuf, ...)
{
int i;
int rank = odom->rank;
int firstdim = (index == 0); /* first dimension*/
int lastdim = (index == (rank - 1)); /* last dimension*/
size_t count;
Symbol* basetype = vsym->typ.basetype;
int isunlimited = (odom->declsize[index] == 0);
int pushed = 0;
ASSERT(index >= 0 && index < rank);
count = odom->count[index];
/* Unpack the nested unlimited (unless first dimension)*/
if(!firstdim && isunlimited && issublist(src)) {
srcpush(src);
pushed = 1;
}
if(lastdim) {
for(i=0;i<count;i++) {
jdata_basetype(basetype,src,databuf,fillsrc);
}
} else {
/* now walk count elements and generate recursively */
for(i=0;i<count;i++) {
jdata_array(vsym,databuf,src,odom,index+1,fillsrc);
}
}
if(isunlimited && pushed) srcpop(src);
return;
/* Escapes and quoting will be handled in genc_write */
/* Just transfer charbuf to codebuf */
Bytebuffer* charbuf;
va_list ap;
vastart(ap,codebuf);
charbuf = va_arg(ap, Bytebuffer*);
va_end(ap);
bbNull(charbuf);
bbCatbuf(codebuf,charbuf);
return 1;
}
/* Generate an instance of the basetype using datasrc */
void
jdata_basetype(Symbol* tsym, Datasrc* datasrc, Bytebuffer* codebuf, Datalist* fillsrc)
static int
j_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
{
switch (tsym->subclass) {
Bytebuffer* codetmp = bbNew();
char* special = NULL;
case NC_PRIM:
if(issublist(datasrc)) {
semerror(srcline(datasrc),"Expected primitive found {..}");
}
bbAppend(codebuf,' ');
jdata_primdata(tsym,datasrc,codebuf,fillsrc);
break;
default: PANIC1("jdata_basetype: unexpected subclass %d",tsym->subclass);
}
}
/**************************************************/
static void
jdata_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* databuf, Datalist* fillsrc)
{
Constant target, *prim;
prim = srcnext(src);
if(prim == NULL) prim = &fillconstant;
ASSERT(prim->nctype != NC_COMPOUND);
if(prim->nctype == NC_FILLVALUE) {
Datalist* filler = getfiller(basetype,fillsrc);
ASSERT(filler->length == 1);
srcpushlist(src,filler);
bbAppend(databuf,' ');
jdata_primdata(basetype,src,databuf,NULL);
srcpop(src);
goto done;
}
target.nctype = basetype->typ.typecode;
ASSERT(prim->nctype != NC_COMPOUND);
convert1(prim,&target);
/* add hack for java bug in converting floats */
if(target.nctype == NC_FLOAT) bbCat(databuf," (float)");
bbCat(databuf,jdata_const(&target));
done:
return;
}
/* Result is a pool string or a constant => do not free*/
char*
jdata_const(Constant* ci)
{
char tmp[64];
char* result = NULL;
tmp[0] = '\0';
switch (ci->nctype) {
case NC_CHAR:
{
strcpy(tmp,"'");
escapifychar(ci->value.charv,tmp+1,'\'');
strcat(tmp,"'");
}
break;
switch (con->nctype) {
case NC_BYTE:
sprintf(tmp,"%hhd",ci->value.int8v);
bbprintf(codetmp,"%hhd",con->value.int8v);
break;
case NC_SHORT:
sprintf(tmp,"%hd",ci->value.int16v);
bbprintf(codetmp,"%hd",con->value.int16v);
break;
case NC_INT:
sprintf(tmp,"%d",ci->value.int32v);
bbprintf(codetmp,"%d",con->value.int32v);
break;
case NC_FLOAT:
sprintf(tmp,"%.8g",ci->value.floatv);
bbprintf(codetmp,"%f",con->value.floatv);
break;
case NC_DOUBLE:
sprintf(tmp,"%.16g",ci->value.doublev);
bbprintf(codetmp,"%lf",con->value.doublev);
break;
case NC_STRING:
{
char* escaped = escapify(ci->value.stringv.stringv,
'"',ci->value.stringv.len);
result = poolalloc(1+2+strlen(escaped));
strcpy(result,"\"");
strcat(result,escaped);
strcat(result,"\"");
goto done;
}
case NC_UBYTE:
bbprintf(codetmp,"%hhu",con->value.uint8v);
break;
case NC_USHORT:
bbprintf(codetmp,"%hu",con->value.uint16v);
break;
case NC_UINT:
bbprintf(codetmp,"%uU",con->value.uint32v);
break;
case NC_INT64:
bbprintf(codetmp,"%lldLL",con->value.int64v);
break;
case NC_UINT64:
bbprintf(codetmp,"%lluLLU",con->value.uint64v);
break;
case NC_STRING: { /* handle separately */
char* escaped = escapify(con->value.stringv.stringv,
'"',con->value.stringv.len);
special = poolalloc(1+2+strlen(escaped));
strcpy(special,"\"");
strcat(special,escaped);
strcat(special,"\"");
} break;
default: PANIC1("ncstype: bad type code: %d",con->nctype);
default: PANIC1("ncstype: bad type code: %d",ci->nctype);
}
result = pooldup(tmp);
done:
return result; /*except for NC_STRING and NC_OPAQUE*/
if(special == NULL)
bbCatbuf(buf,codetmp);
else
bbCat(buf,special);
bbFree(codetmp);
return 1;
}
static int
j_listbegin(Generator* generator, ListClass lc, size_t size, Bytebuffer* codebuf, int* uidp, ...)
{
if(uidp) *uidp = ++j_uid;
switch (lc) {
case LISTATTR:
case LISTDATA:
break;
case LISTFIELDARRAY:
case LISTVLEN:
case LISTCOMPOUND:
break;
}
return 1;
}
static int
j_list(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* codebuf, ...)
{
switch (lc) {
case LISTATTR:
if(count > 0) bbCat(codebuf,", ");
break;
case LISTDATA:
bbCat(codebuf," ");
break;
case LISTVLEN:
case LISTCOMPOUND:
case LISTFIELDARRAY:
break;
}
return 1;
}
static int
j_listend(Generator* generator, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...)
{
return 1;
}
static int
j_vlendecl(Generator* generator, Bytebuffer* codebuf, Symbol* tsym, int uid, size_t count, ...)
{
return 1;
}
static int
j_vlenstring(Generator* generator, Bytebuffer* vlenmem, int* uidp, size_t* countp,...)
{
if(uidp) *uidp = ++j_uid;
if(countp) *countp = 0;
return 1;
}
/* Define the single static bin data generator */
static Generator j_generator_singleton = {
NULL,
j_charconstant,
j_constant,
j_listbegin,
j_list,
j_listend,
j_vlendecl,
j_vlenstring
};
Generator* j_generator = &j_generator_singleton;
#endif /*ENABLE_JAVA*/

View File

@ -22,17 +22,24 @@ extern int ncgparse(void);
char* progname;
char* cdlname;
int kflag_flag; /* 1 => -k was specified on command line*/
int cmode_modifier;
/* option flags */
int nofill_flag;
char* mainname; /* name to use for main function; defaults to "main"*/
int c_flag;
int binary_flag;
int f77_flag;
int cml_flag;
int java_flag; /* 1=> use netcdf java interface (=>usingclassic)*/
int java_flag; /* 1=> use netcdf java interface */
int syntax_only;
/* flags for tracking what output format to use */
int k_flag; /* > 0 => -k was specified on command line*/
int format_flag; /* _Format attribute value (same range as -k flag) */
int enhanced_flag; /* 1 => netcdf-4 constructs appear in the parse */
int specials_flag; /* 1=> special attributes are present */
int usingclassic;
int cmode_modifier;
size_t nciterbuffersize;
struct Vlendata* vlendata;
@ -40,39 +47,36 @@ struct Vlendata* vlendata;
char *netcdf_name; /* command line -o file name */
char *datasetname; /* name from the netcdf <name> {} */
/* Misc. flags*/
int usingclassic;
int allowspecial; /* are special attributes ok to use */
extern FILE *ncgin;
/* Forward */
static char* ubasename ( const char* av0 );
void usage ( void );
int main ( int argc, char** argv );
static char* ubasename(char*);
void usage( void );
int main( int argc, char** argv );
/* Define tables vs modes for legal -k values*/
struct Kvalues legalkinds[NKVALUES] = {
{"1", 0},
{"classic", 0},
{"1", 1},
{"classic", 1},
/* The 64-bit offset kind (2) should only be used if actually needed */
{"2", NC_64BIT_OFFSET},
{"64-bit-offset", NC_64BIT_OFFSET},
{"64-bit offset", NC_64BIT_OFFSET},
{"2", 2},
{"64-bit-offset", 2},
{"64-bit offset", 2},
/* NetCDF-4 HDF5 format*/
{"3", NC_NETCDF4},
{"hdf5", NC_NETCDF4},
{"netCDF-4", NC_NETCDF4},
{"netcdf-4", NC_NETCDF4},
{"netcdf4", NC_NETCDF4},
{"enhanced", NC_NETCDF4},
{"3", 3},
{"hdf5", 3},
{"netCDF-4", 3},
{"netcdf-4", 3},
{"netcdf4", 3},
{"enhanced", 3},
/* NetCDF-4 HDF5 format, but using only nc3 data model */
{"4", NC_NETCDF4 | NC_CLASSIC_MODEL},
{"hdf5-nc3", NC_NETCDF4 | NC_CLASSIC_MODEL},
{"netCDF-4 classic model", NC_NETCDF4 | NC_CLASSIC_MODEL},
{"enhanced-nc3", NC_NETCDF4 | NC_CLASSIC_MODEL},
{"4", 4},
{"hdf5-nc3", 4},
{"netCDF-4 classic model", 4},
{"enhanced-nc3", 4},
/* null terminate*/
{NULL,0}
@ -104,9 +108,8 @@ struct Languages {
/* result is malloc'd */
static char *
ubasename(const char *av0)
ubasename(char *logident)
{
char *logident = nulldup(av0);
char* sep;
sep = strrchr(logident,'/');
@ -151,13 +154,16 @@ main(
cml_flag = 0;
java_flag = 0;
binary_flag = 0;
kflag_flag = 0;
cmode_modifier = 0;
nofill_flag = 0;
syntax_only = 0;
mainname = "main";
nciterbuffersize = 0;
k_flag = 0;
format_flag = 0;
enhanced_flag = 0;
specials_flag = 0;
#if _CRAYMPP && 0
/* initialize CRAY MPP parallel-I/O library */
(void) par_io_init(32, 32);
@ -234,7 +240,7 @@ main(
(void)strcpy(kind_name, optarg);
for(kvalue=legalkinds;kvalue->name;kvalue++) {
if(strcmp(kind_name,kvalue->name) == 0) {
cmode_modifier = kvalue->mode;
k_flag = kvalue->k_flag;
break;
}
}
@ -242,7 +248,6 @@ main(
derror("Invalid format: %s",kind_name);
return 2;
}
kflag_flag = 1;
}
break;
case 'M': /* Determine the name for the main function */
@ -269,7 +274,7 @@ main(
if(languages == 0) {
binary_flag = 1; /* default */
if(kflag_flag == 0)
if(k_flag == 0)
syntax_only = 1;
}
@ -329,30 +334,6 @@ main(
if(strlen(cdlname) > NC_MAX_NAME) cdlname[NC_MAX_NAME] = '\0';
}
/* Initially set up the cmode value and related items*/
if(kflag_flag == 0) cmode_modifier = DFALTCMODE;
usingclassic = 0;
allowspecial = 0;
/* Do first pass on flags */
if((cmode_modifier & NC_NETCDF4) != 0) {
allowspecial = 1;
if((cmode_modifier & NC_CLASSIC_MODEL)) {
usingclassic = 1;
} else {
usingclassic = 0;
}
} else {
usingclassic = 1;
}
/* F77 || STD java => classic */
if(f77_flag || java_flag) {
usingclassic=1;
cmode_modifier &= ~(NC_NETCDF4);
}
/* Standard Unidata java interface => usingclassic */
parse_init();
@ -360,31 +341,55 @@ main(
if(debug >= 2) {ncgdebug=1;}
if(ncgparse() != 0) return 1;
/* Recompute flags */
if((cmode_modifier & NC_NETCDF4) != 0) {
allowspecial = 1;
if((cmode_modifier & NC_CLASSIC_MODEL)) {
usingclassic = 1;
} else {
usingclassic = 0;
}
} else {
usingclassic = 1;
}
/* Complain if still usingclassic =1 && a cdf4
construct was used
*/
if(usingclassic && getmarkcdf4() != NULL) {
verror(getmarkcdf4());
return 1;
}
/* Compute the k_flag (1st pass) using rules in the man page (ncgen.1).*/
#ifndef USE_NETCDF4
allowspecial = 0;
if(enhanced_flag) {
derror("CDL input is enhanced mode, but --disable-netcdf4 was specified during build");
return 0;
}
#endif
if(java_flag || f77_flag) {
k_flag = 1;
if(enhanced_flag) {
derror("Java or Fortran requires classic model CDL input");
return 0;
}
}
if(k_flag == 0)
k_flag = format_flag;
if(enhanced_flag && k_flag == 0)
k_flag = 3;
if(enhanced_flag && k_flag != 3) {
derror("-k or _Format conflicts with enhanced CDL input");
return 0;
}
if(specials_flag && k_flag == 0)
#ifdef USE_NETCDF4
k_flag = 4;
#else
k_flag = 1;
#endif
if(k_flag == 0)
k_flag = 1;
usingclassic = (k_flag <= 2?1:0);
/* compute cmode_modifier */
switch (k_flag) {
case 1: cmode_modifier = 0; break;
case 2: cmode_modifier = NC_64BIT_OFFSET; break;
case 3: cmode_modifier = NC_NETCDF4; break;
case 4: cmode_modifier = NC_NETCDF4 | NC_CLASSIC_MODEL; break;
default: ASSERT(0); /* cannot happen */
}
processsemantics();
if(!syntax_only)
define_netcdf();

View File

@ -77,8 +77,7 @@ The possible arguments are as follows.
.IP "'4', 'hdf5-nc3', 'netCDF-4 classic model', 'enhanced-nc3' => netcdf-4 file format, netcdf-3 type model."
.RE
.RE
If no -k is specified then it defaults to -k1 (i.e. classic).
Note also that -v is accepted to mean the same thing as
Note that -v is accepted to mean the same thing as
-k for backward compatibility, but -k is preferred, to match
the corresponding ncdump option.
.IP "\fB-x\fP"
@ -101,6 +100,43 @@ The currently supported languages have the following flags.
only the classic model is supported.
.RE
.RE
.SH Choosing the output format
The choice of output format is determined by three flags.
.IP "\fB-k flag.\fP"
.IP "\fB_Format attribute (see below).\fP"
.IP "\fBOccurrence of netcdf-4 constructs in the input CDL.\fP"
The term "netCDF-4 constructs" means
construct from the enhanced data model,
not just special performance-related attributes such as
_ChunkSizes, _DeflateLevel, _Endianness, etc.
.LP
The rules are as follows, in order of application.
.IP "\fB1.\fP"
If either Fortran or Java output is specified,
then -k flag value of 1 (classic model) will be used.
Conflicts with the use of enhanced constructs
in the CDL will report an error.
.IP "\fB2.\fP"
If both the -k flag and _Format attribute are specified,
the _Format flag will be ignored.
If no -k flag is specified, and a _Format attribute value
is specified, then the -k flag value
will be set to that of the _Format attribute.
Otherwise the -k flag is undefined.
.IP "\fB3.\fP"
If the -k option is defined and is consistent with the CDL,
ncgen will output a file in the requested form,
else an error will be reported.
.IP "\fB4.\fP"
If the -k flag is undefined,
and if there are netCDF-4 constructs in the CDL,
a -k flag value of 3 (enhanced model) will be used.
.IP "\fB5.\fP"
If special performance-related attributes are specified in the CDL,
a -k flag value of 4 (netCDF-4 classic model) will be used.
.IP "\fB6.\fP"
Otherwise ncgen will set the -k flag to 1 (classic model).
.RE
.SH EXAMPLES
.LP
Check the syntax of the CDL file `\fBfoo.cdl\fP':
@ -688,60 +724,50 @@ and we have three strings of length 1, 3, 5.
How do we assign the characters in the strings to the
twenty elements?
.LP
The basic rule is "greedy" plus "right dimension rules".
By this we mean the following.
This is challenging because it is desirable to mimic
the original ncgen (ncgen3).
The core algorithm is notionally as follows.
.IP 1. 3
Use the size of the rightmost dimension (d4=4)
and modify the constant list so that every string is less
than or equal to this dimension size. Longer strings are decomposed.
For our example, we get this.
.in +5
datalist: var= "1", "two", "thre", "e";
.in -5
Assume we have a set of dimensions D1..Dn,
where D1 may optionally be an Unlimited dimension.
It is assumed that the sizes of the Di are all known
(including unlimited dimensions).
.IP 2. 3
Pad any short strings to the length of the right dimension.
This produces the following.
.in +5
datalist: var= "1\\0\\0\\0", "two\\0", "thre", "e\\0\\0\\0";
.in -5
Given a sequence of string or character constants
C1..Cm, our goal is to construct a single string
whose length is the cross product of D1 thru Dn.
Note that for purposes of this algorithm, character constants
are treated as strings of size 1.
.IP 3. 3
Move the the next to the rightmost dimension (d5 in this case)
and add fill values as needed, producing this.
.in +5
datalist: var= "1\\0\\0\\0", "two\\0", "thre", "e\\0\\0\\0", "\\0\\0\\0\\0";
.in -5
4. Repeat step 3 for successively more left dimensions until the
first dimension is reached. If the first dimension is UNLIMITED,
and has not had any previous value assigned to it, then
do not pad, but instead use the length at that point
as the unlimited length. In all other cases, pad to the
specified length.
Construct Dx = cross product of D1 thru D(n-1).
.IP 4. 3
For each constant Ci, add fill characters as needed
so that its length is a multiple of Dn.
.IP 5. 3
Concatenate the modified C1..Cm to produce string S.
.IP 6. 3
Add fill characters to S to make its length be a multiple of Dn.
.IP 8. 3
If S is longer than the Dx * Dn, then truncate
and generate a warning.
.LP
Note that the term "greedy" is used because the above algorithm
causes the strings to be assigned to the "front" of the variable
and fill values to the end.
.LP
There are several additional edge cases that must be dealt with.
There are three other cases of note.
.IP 1. 3
Suppose we have only an unlimited dimension such as this case.
.in +5
.nf
variables: char var(u);
datalist: var="1", "two", "three";
.fi
.in -5
In this case, we treat it like it was defined as this.
.in +5
.nf
variables: char var(u,d1);
datalist: var="1","t","w","o","t","h","r","e","e";
.fi
.in -5
This means that u will have the length of nine.
If there is only a single, unlimited dimension,
then all of the constants are concatenated
and fill characers are added to the
end of the resulting string to make its
length be that of the unlimited dimension.
If the length is larger than
the unlimited dimension, then it is truncated
with a warning.
.IP 2. 3
For the case of character typed vlen, "char(*) vlen_t" for example.
we simply concatenate all the constants with no filling at all.
.IP 3. 3
For the case of a character typed attribute,
we simply concatenate all the constants.
.LP
In netcdf-4, dimensions other than the first can be unlimited.
Of course by the rules above, the interior unlimited instances
must be delimited by {...}. For example.
@ -751,14 +777,12 @@ variables: char var(u,u2);
datalist: var={"1", "two"}, {"three"};
.fi
.in -5
In this case u will have the effective length of two.
Within each instance of u2, the rules above will apply, leading
to this.
.in +5
datalist: var={"1","t","w","o"}, {"t","h","r","e","e"};
.in -5
The effective size of u2 will be the max of the two instance lengths
(five in this case)
and the shorter will be padded to produce this.

View File

@ -82,16 +82,16 @@ various C global variables
struct Kvalues {
char* name;
int mode;
int k_flag;
};
#define NKVALUES 16
extern struct Kvalues legalkinds[NKVALUES];
/* Note: non-variable specials (e.g. _Format) are not included in this struct*/
/* Note: some non-var specials (i.e. _Format) are not included in this struct*/
typedef struct Specialdata {
int flags;
Datalist* _Fillvalue;
Datalist* _Fillvalue; /* This is a per-type */
int _Storage; /* NC_CHUNKED | NC_CONTIGUOUS*/
size_t* _ChunkSizes; /* NULL => defaults*/
int nchunks; /* |_Chunksize| ; 0 => not specified*/
@ -111,7 +111,7 @@ typedef struct Dimset {
typedef struct Diminfo {
int isconstant; /* separate constant from named dimension*/
size_t unlimitedsize; /* if unlimited */
int isunlimited;
size_t declsize; /* 0 => unlimited/unspecified*/
} Diminfo;
@ -130,6 +130,8 @@ typedef struct Typeinfo {
size_t size; /* for opaque, compound, etc.*/
size_t nelems; /* size in terms of # of datalist constants
it takes to represent it */
Datalist* _Fillvalue; /* per-type cached fillvalue
(overridden by var fillvalue) */
} Typeinfo;
typedef struct Varinfo {
@ -140,7 +142,6 @@ typedef struct Varinfo {
typedef struct Groupinfo {
int is_root;
struct Symbol* unlimiteddim;
} Groupinfo;
typedef struct Symbol { /* symbol table entry*/

View File

@ -14,7 +14,7 @@
8859 characters above 128 will be handles as n-byte utf8 and so
will probably not lex correctly.
Solution: assume utf8 and note in the documentation that
ISO8859 is specifically unsupported (except as noted below).
ISO8859 is specifically unsupported.
2. The netcdf function NC_check_name in string.c must be modified to
conform to the use of UTF8.
3. We actually have three tests for UTF8 of increasing correctness
@ -24,7 +24,8 @@
http://www.w3.org/2005/03/23-lex-U
We include lexical definitions for all three, but use the second version.
4. Single character constants enclosed in '...' cannot be
utf-8, so we assume they are the one case where ISO-8859-1 is allowed.
utf-8, so we assume they are the one case where US-Ascii (7-bit) is used.
We could use ISO-8859-1, but that conflicts with UTF-8 above value 127.
*/
/* lex specification for tokens for ncgen */
@ -40,7 +41,7 @@
char errstr[100]; /* for short error messages */
int lineno; /* line number for error messages */
char* lextext; /* name or string with escapes removed */
Bytebuffer* lextext; /* name or string with escapes removed */
#define YY_BREAK /* defining as nothing eliminates unreachable
statement warnings from flex output,
@ -159,7 +160,7 @@ FLTNUMBER [+-]?[0-9]*\.[0-9]*{exp}?[Ff]|[+-]?[0-9]*{exp}[Ff]
SPECIAL "_FillValue"|"_Format"|"_Storage"|"_ChunkSizes"|"_Fletcher32"|"_DeflateLevel"|"_Shuffle"|"_Endianness"|"_NoFill"
ISO8859CHAR [\x01-\xFF]
USASCII [\x01-\x7F]
%%
[ \r\t\f]+ { /* whitespace */
@ -179,10 +180,10 @@ yyerror("string too long, truncated\n");
yytext[MAXTRST-1] = '\0';
}
*/
lextext = emalloc(1+4*yyleng); /* should be max
needed */
/* Assumes expand escapes also does normalization */
bbClear(lextext);
expand_escapes(lextext,(char *)yytext,yyleng);
bbNull(lextext);
return lexdebug(TERMSTRING);
}
@ -191,12 +192,11 @@ yytext[MAXTRST-1] = '\0';
int len = yyleng - 2;
int padlen = len;
if((padlen % 2) == 1) padlen++;
lextext = emalloc(1+padlen);
strncpy(lextext,p,len+1); /*include null */
lextext[len] = '0'; /* assume padding */
lextext[padlen] = '\0'; /* make sure null terminated */
bbClear(lextext);
bbAppendn(lextext,p,len);
bbNull(lextext);
/* convert all chars to lower case */
for(p=lextext;*p;p++) *p = tolower(*p);
for(p=bbContents(lextext);*p;p++) *p = tolower(*p);
return lexdebug(OPAQUESTRING);
}
@ -257,19 +257,20 @@ NaNf|nanf { /* missing value (pre-2.4 backward compatibility) */
}
{PATH} {
lextext = emalloc(1+4*yyleng); /* should be max needed */
strncpy(lextext,(char*)yytext,yyleng+1); /* include null */
yylval.sym = makepath(lextext);
free(lextext);
bbClear(lextext);
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */
bbNull(lextext);
yylval.sym = makepath(bbContents(lextext));
return lexdebug(PATH);
}
{SPECIAL} {struct Specialtoken* st;
lextext = emalloc(1+4*yyleng); /* should be max needed */
strncpy(lextext,(char*)yytext,yyleng+1); /* include null */
bbClear(lextext);
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */
bbNull(lextext);
for(st=specials;st->name;st++) {
if(strcmp(lextext,st->name)==0) {return lexdebug(st->token);}
if(strcmp(bbContents(lextext),st->name)==0) {return lexdebug(st->token);}
}
return 0;
}
@ -277,24 +278,27 @@ NaNf|nanf { /* missing value (pre-2.4 backward compatibility) */
<TEXT>{DATASETID} {
int c;
char* p; char* q;
lextext = emalloc(1+4*yyleng); /* should be max needed */
/* copy the trimmed name */
strncpy(lextext,(char*)yytext,yyleng+1); /* include null */
p = lextext;
q = lextext;
bbClear(lextext);
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */
bbNull(lextext);
p = bbContents(lextext);
q = p;
while((c=*p++)) {if(c > ' ') *q++ = c;}
*q = '\0';
datasetname = lextext;
datasetname = bbDup(lextext);
BEGIN(INITIAL);
return lexdebug(DATASETID);
}
{ID} {
lextext = emalloc(1+4*yyleng); /* should be max needed */
strncpy(lextext,(char*)yytext,yyleng+1); /* include null */
deescapify(lextext);
if (STREQ((char *)lextext, FILL_STRING)) return lexdebug(FILLMARKER);
yylval.sym = install(lextext);
{ID} { char* id;
bbClear(lextext);
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */
bbNull(lextext);
id = bbContents(lextext);
deescapify(id);
if (STREQ(id, FILL_STRING)) return lexdebug(FILLMARKER);
yylval.sym = install(id);
return lexdebug(IDENT);
}
@ -559,7 +563,7 @@ int
lex_init(void)
{
lineno = 1;
lextext = NULL;
lextext = bbNew();
if(0) unput(0); /* keep -Wall quiet */
return 0;
}

View File

@ -71,7 +71,7 @@ char* primtypenames[PRIMNO] = {
/*Defined in ncgen.l*/
extern int lineno; /* line number for error messages */
extern char* lextext; /* name or string with escapes removed */
extern Bytebuffer* lextext; /* name or string with escapes removed */
extern double double_val; /* last double value read */
extern float float_val; /* last float value read */
@ -101,8 +101,6 @@ static Constant makeconstdata(nc_type);
static Constant evaluate(Symbol* fcn, Datalist* arglist);
static Constant makeenumconst(Symbol*);
static void addtogroup(Symbol*);
static Symbol* getunlimiteddim(void);
static void setunlimiteddim(Symbol* udim);
static Symbol* currentgroup(void);
static Symbol* createrootgroup(void);
static Symbol* creategroup(Symbol*);
@ -440,6 +438,9 @@ dimdecl:
dimd '=' UINT_CONST
{
$1->dim.declsize = (size_t)uint32_val;
#ifdef DEBUG1
fprintf(stderr,"dimension: %s = %lu\n",$1->name,(unsigned long)$1->dim.declsize);
#endif
}
| dimd '=' INT_CONST
{
@ -448,6 +449,9 @@ dimdecl:
YYABORT;
}
$1->dim.declsize = (size_t)int32_val;
#ifdef DEBUG1
fprintf(stderr,"dimension: %s = %lu\n",$1->name,(unsigned long)$1->dim.declsize);
#endif
}
| dimd '=' DOUBLE_CONST
{ /* for rare case where 2^31 < dimsize < 2^32 */
@ -458,16 +462,17 @@ dimdecl:
if (double_val - (size_t) double_val > 0)
yyerror("dimension length must be an integer");
$1->dim.declsize = (size_t)double_val;
#ifdef DEBUG1
fprintf(stderr,"dimension: %s = %lu\n",$1->name,(unsigned long)$1->dim.declsize);
#endif
}
| dimd '=' NC_UNLIMITED_K
{
if(usingclassic) {
/* check for multiple UNLIMITED decls*/
if(getunlimiteddim() != NULL)
markcdf4("Type specification");
setunlimiteddim($1);
}
$1->dim.declsize = NC_UNLIMITED;
$1->dim.declsize = NC_UNLIMITED;
$1->dim.isunlimited = 1;
#ifdef DEBUG1
fprintf(stderr,"dimension: %s = UNLIMITED\n",$1->name);
#endif
}
;
@ -782,7 +787,7 @@ datalist:
;
datalist0:
/*empty*/ {$$ = builddatalist(0);}
/*empty*/ {$$ = NULL;}
;
datalist1: /* Must have at least 1 element */
@ -954,18 +959,6 @@ install(const char *sname)
}
static void
setunlimiteddim(Symbol* udim)
{
rootgroup->grp.unlimiteddim = udim;
}
static Symbol*
getunlimiteddim(void)
{
return rootgroup->grp.unlimiteddim;
}
static Symbol*
currentgroup(void)
{
@ -981,7 +974,6 @@ createrootgroup(void)
gsym->container = NULL;
gsym->subnodes = listnew();
gsym->grp.is_root = 1;
gsym->grp.unlimiteddim = NULL;
gsym->prefix = listnew();
listpush(grpdefs,(elem_t)gsym);
rootgroup = gsym;
@ -1024,9 +1016,10 @@ makeconstdata(nc_type nctype)
break;
case NC_STRING: { /* convert to a set of chars*/
int len;
len = strlen(lextext);
len = bbLength(lextext);
con.value.stringv.len = len;
con.value.stringv.stringv = nulldup(lextext);
con.value.stringv.stringv = bbDup(lextext);
bbClear(lextext);
}
break;
@ -1041,14 +1034,14 @@ makeconstdata(nc_type nctype)
case NC_OPAQUE: {
char* s;
int len,padlen;
len = strlen(lextext);
len = bbLength(lextext);
padlen = len;
if(padlen < 16) padlen = 16;
if((padlen % 2) == 1) padlen++;
s = (char*)emalloc(padlen+1);
memset((void*)s,'0',padlen);
s[padlen]='\0';
strncpy(s,lextext,len);
strncpy(s,bbContents(lextext),len);
con.value.opaquev.stringv = s;
con.value.opaquev.len = padlen;
} break;
@ -1070,9 +1063,7 @@ static Constant
makeenumconst(Symbol* econst)
{
Constant con;
if(usingclassic) {
markcdf4("Enum type");
}
markcdf4("Enum type");
consttype = NC_ENUM;
con.nctype = NC_ECONST;
con.lineno = lineno;
@ -1185,6 +1176,8 @@ makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst)
char* sdata = NULL;
int idata = -1;
specials_flag = 1;
if(isconst) {
con = (Constant*)data;
list = builddatalist(1);
@ -1236,35 +1229,17 @@ makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst)
if(tag == _FORMAT_FLAG) {
struct Kvalues* kvalue;
int found;
int modifier;
found = 0;
modifier = 0;
if(kflag_flag != 0) goto done;
/* Only use this tag if kflag is not set */
/* Use the table in main.c */
for(kvalue=legalkinds;kvalue->name;kvalue++) {
if(strcmp(sdata,kvalue->name) == 0) {
modifier = kvalue->mode;
format_flag = kvalue->k_flag;
found = 1;
break;
}
}
if(!found)
derror("_Format: illegal value: %s",sdata);
else {
/* Recompute mode flag */
cmode_modifier &= ~(NC_NETCDF4 | NC_CLASSIC_MODEL | NC_64BIT_OFFSET);
cmode_modifier |= modifier;
if((cmode_modifier & NC_NETCDF4)) {
allowspecial = 1;
if((cmode_modifier & NC_CLASSIC_MODEL)) {
usingclassic = 1;
} else {
usingclassic = 0;
}
} else
usingclassic = 1;
}
} else if(tag == _FILLVALUE_FLAG) {
special->_Fillvalue = list;
/* fillvalue must be a single value*/
@ -1338,7 +1313,7 @@ makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst)
} break;
default: PANIC1("makespecial: illegal token: %d",tag);
}
done:
return attr;
}
@ -1375,12 +1350,14 @@ makeattribute(Symbol* asym,
static int
containsfills(Datalist* list)
{
int i;
Constant* con = list->data;
for(i=0;i<list->length;i++,con++) {
if(con->nctype == NC_COMPOUND) {
if(containsfills(con->value.compoundv)) return 1;
} else if(con->nctype == NC_FILLVALUE) return 1;
if(list != NULL) {
int i;
Constant* con = list->data;
for(i=0;i<list->length;i++,con++) {
if(con->nctype == NC_COMPOUND) {
if(containsfills(con->value.compoundv)) return 1;
} else if(con->nctype == NC_FILLVALUE) return 1;
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1211,7 +1211,7 @@ char *ncgtext;
8859 characters above 128 will be handles as n-byte utf8 and so
will probably not lex correctly.
Solution: assume utf8 and note in the documentation that
ISO8859 is specifically unsupported (except as noted below).
ISO8859 is specifically unsupported.
2. The netcdf function NC_check_name in string.c must be modified to
conform to the use of UTF8.
3. We actually have three tests for UTF8 of increasing correctness
@ -1221,7 +1221,8 @@ char *ncgtext;
http://www.w3.org/2005/03/23-lex-U
We include lexical definitions for all three, but use the second version.
4. Single character constants enclosed in '...' cannot be
utf-8, so we assume they are the one case where ISO-8859-1 is allowed.
utf-8, so we assume they are the one case where US-Ascii (7-bit) is used.
We could use ISO-8859-1, but that conflicts with UTF-8 above value 127.
*/
/* lex specification for tokens for ncgen */
@ -1237,7 +1238,7 @@ char *ncgtext;
char errstr[100]; /* for short error messages */
int lineno; /* line number for error messages */
char* lextext; /* name or string with escapes removed */
Bytebuffer* lextext; /* name or string with escapes removed */
#define YY_BREAK /* defining as nothing eliminates unreachable
statement warnings from flex output,
@ -1320,7 +1321,7 @@ ID ([A-Za-z_]|{UTF8})([A-Z.@#\[\]a-z_0-9+-]|{UTF8})*
/* Note: this definition of string will work for utf8 as well,
although it is a very relaxed definition
*/
#line 1324 "lex.ncg.c"
#line 1325 "lex.ncg.c"
#define INITIAL 0
#define ST_C_COMMENT 1
@ -1411,7 +1412,7 @@ static int input (void );
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
#define ECHO fwrite( ncgtext, ncgleng, 1, ncgout )
#define ECHO do { if (fwrite( ncgtext, ncgleng, 1, ncgout )) {} } while (0)
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
@ -1422,7 +1423,7 @@ static int input (void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
int n; \
unsigned n; \
for ( n = 0; n < max_size && \
(c = getc( ncgin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@ -1504,9 +1505,9 @@ YY_DECL
register char *yy_cp, *yy_bp;
register int yy_act;
#line 164 "ncgen.l"
#line 165 "ncgen.l"
#line 1510 "lex.ncg.c"
#line 1511 "lex.ncg.c"
if ( !(yy_init) )
{
@ -1591,14 +1592,14 @@ do_action: /* This label is used only to access EOF actions. */
case 1:
YY_RULE_SETUP
#line 165 "ncgen.l"
#line 166 "ncgen.l"
{ /* whitespace */
break;
}
YY_BREAK
case 2:
YY_RULE_SETUP
#line 169 "ncgen.l"
#line 170 "ncgen.l"
{ /* comment */
break;
}
@ -1606,7 +1607,7 @@ YY_RULE_SETUP
case 3:
/* rule 3 can match eol */
YY_RULE_SETUP
#line 173 "ncgen.l"
#line 174 "ncgen.l"
{
/* In netcdf4, this will be used in a variety
of places, so only remove escapes */
@ -1616,27 +1617,26 @@ yyerror("string too long, truncated\n");
ncgtext[MAXTRST-1] = '\0';
}
*/
lextext = emalloc(1+4*ncgleng); /* should be max
needed */
/* Assumes expand escapes also does normalization */
bbClear(lextext);
expand_escapes(lextext,(char *)ncgtext,ncgleng);
bbNull(lextext);
return lexdebug(TERMSTRING);
}
YY_BREAK
case 4:
YY_RULE_SETUP
#line 189 "ncgen.l"
#line 190 "ncgen.l"
{ /* drop leading 0x; pad to even number of chars */
char* p = ncgtext+2;
int len = ncgleng - 2;
int padlen = len;
if((padlen % 2) == 1) padlen++;
lextext = emalloc(1+padlen);
strncpy(lextext,p,len+1); /*include null */
lextext[len] = '0'; /* assume padding */
lextext[padlen] = '\0'; /* make sure null terminated */
bbClear(lextext);
bbAppendn(lextext,p,len);
bbNull(lextext);
/* convert all chars to lower case */
for(p=lextext;*p;p++) *p = tolower(*p);
for(p=bbContents(lextext);*p;p++) *p = tolower(*p);
return lexdebug(OPAQUESTRING);
}
YY_BREAK
@ -1794,10 +1794,10 @@ case 30:
YY_RULE_SETUP
#line 259 "ncgen.l"
{
lextext = emalloc(1+4*ncgleng); /* should be max needed */
strncpy(lextext,(char*)ncgtext,ncgleng+1); /* include null */
yylval.sym = makepath(lextext);
free(lextext);
bbClear(lextext);
bbAppendn(lextext,(char*)ncgtext,ncgleng+1); /* include null */
bbNull(lextext);
yylval.sym = makepath(bbContents(lextext));
return lexdebug(PATH);
}
YY_BREAK
@ -1805,10 +1805,11 @@ case 31:
YY_RULE_SETUP
#line 268 "ncgen.l"
{struct Specialtoken* st;
lextext = emalloc(1+4*ncgleng); /* should be max needed */
strncpy(lextext,(char*)ncgtext,ncgleng+1); /* include null */
bbClear(lextext);
bbAppendn(lextext,(char*)ncgtext,ncgleng+1); /* include null */
bbNull(lextext);
for(st=specials;st->name;st++) {
if(strcmp(lextext,st->name)==0) {return lexdebug(st->token);}
if(strcmp(bbContents(lextext),st->name)==0) {return lexdebug(st->token);}
}
return 0;
}
@ -1816,37 +1817,40 @@ YY_RULE_SETUP
case 32:
/* rule 32 can match eol */
YY_RULE_SETUP
#line 277 "ncgen.l"
#line 278 "ncgen.l"
{
int c;
char* p; char* q;
lextext = emalloc(1+4*ncgleng); /* should be max needed */
/* copy the trimmed name */
strncpy(lextext,(char*)ncgtext,ncgleng+1); /* include null */
p = lextext;
q = lextext;
bbClear(lextext);
bbAppendn(lextext,(char*)ncgtext,ncgleng+1); /* include null */
bbNull(lextext);
p = bbContents(lextext);
q = p;
while((c=*p++)) {if(c > ' ') *q++ = c;}
*q = '\0';
datasetname = lextext;
datasetname = bbDup(lextext);
BEGIN(INITIAL);
return lexdebug(DATASETID);
}
YY_BREAK
case 33:
YY_RULE_SETUP
#line 292 "ncgen.l"
{
lextext = emalloc(1+4*ncgleng); /* should be max needed */
strncpy(lextext,(char*)ncgtext,ncgleng+1); /* include null */
deescapify(lextext);
if (STREQ((char *)lextext, FILL_STRING)) return lexdebug(FILLMARKER);
yylval.sym = install(lextext);
#line 294 "ncgen.l"
{ char* id;
bbClear(lextext);
bbAppendn(lextext,(char*)ncgtext,ncgleng+1); /* include null */
bbNull(lextext);
id = bbContents(lextext);
deescapify(id);
if (STREQ(id, FILL_STRING)) return lexdebug(FILLMARKER);
yylval.sym = install(id);
return lexdebug(IDENT);
}
YY_BREAK
case 34:
YY_RULE_SETUP
#line 301 "ncgen.l"
#line 305 "ncgen.l"
{
/* We need to try to see what size of integer ((u)int). */
/* Technically, the user should specify, but... */
@ -1898,7 +1902,7 @@ YY_RULE_SETUP
YY_BREAK
case 35:
YY_RULE_SETUP
#line 350 "ncgen.l"
#line 354 "ncgen.l"
{ /* The number may be signed or unsigned (signed has priority) */
int slen = strlen(ncgtext);
int tag = ncgtext[slen-1];
@ -1953,7 +1957,7 @@ YY_RULE_SETUP
YY_BREAK
case 36:
YY_RULE_SETUP
#line 402 "ncgen.l"
#line 406 "ncgen.l"
{
int slen = strlen(ncgtext);
int tag = ncgtext[slen-1];
@ -1996,7 +2000,7 @@ YY_RULE_SETUP
YY_BREAK
case 37:
YY_RULE_SETUP
#line 441 "ncgen.l"
#line 445 "ncgen.l"
{
int c;
int token = 0;
@ -2034,7 +2038,7 @@ YY_RULE_SETUP
YY_BREAK
case 38:
YY_RULE_SETUP
#line 475 "ncgen.l"
#line 479 "ncgen.l"
{
if (sscanf((char*)ncgtext, "%le", &double_val) != 1) {
sprintf(errstr,"bad long or double constant: %s",(char*)ncgtext);
@ -2045,7 +2049,7 @@ YY_RULE_SETUP
YY_BREAK
case 39:
YY_RULE_SETUP
#line 482 "ncgen.l"
#line 486 "ncgen.l"
{
if (sscanf((char*)ncgtext, "%e", &float_val) != 1) {
sprintf(errstr,"bad float constant: %s",(char*)ncgtext);
@ -2057,7 +2061,7 @@ YY_RULE_SETUP
case 40:
/* rule 40 can match eol */
YY_RULE_SETUP
#line 489 "ncgen.l"
#line 493 "ncgen.l"
{
(void) sscanf((char*)&ncgtext[1],"%c",&byte_val);
return lexdebug(BYTE_CONST);
@ -2065,7 +2069,7 @@ YY_RULE_SETUP
YY_BREAK
case 41:
YY_RULE_SETUP
#line 493 "ncgen.l"
#line 497 "ncgen.l"
{
byte_val = (char) strtol((char*)&ncgtext[2], (char **) 0, 8);
return lexdebug(BYTE_CONST);
@ -2073,7 +2077,7 @@ YY_RULE_SETUP
YY_BREAK
case 42:
YY_RULE_SETUP
#line 497 "ncgen.l"
#line 501 "ncgen.l"
{
byte_val = (char) strtol((char*)&ncgtext[3], (char **) 0, 16);
return lexdebug(BYTE_CONST);
@ -2081,7 +2085,7 @@ YY_RULE_SETUP
YY_BREAK
case 43:
YY_RULE_SETUP
#line 501 "ncgen.l"
#line 505 "ncgen.l"
{
switch ((char)ncgtext[2]) {
case 'a': byte_val = '\007'; break; /* not everyone under-
@ -2103,7 +2107,7 @@ YY_RULE_SETUP
case 44:
/* rule 44 can match eol */
YY_RULE_SETUP
#line 519 "ncgen.l"
#line 523 "ncgen.l"
{
lineno++ ;
break;
@ -2111,7 +2115,7 @@ YY_RULE_SETUP
YY_BREAK
case 45:
YY_RULE_SETUP
#line 524 "ncgen.l"
#line 528 "ncgen.l"
{/*initial*/
BEGIN(ST_C_COMMENT);
break;
@ -2120,21 +2124,21 @@ YY_RULE_SETUP
case 46:
/* rule 46 can match eol */
YY_RULE_SETUP
#line 529 "ncgen.l"
#line 533 "ncgen.l"
{/* continuation */
break;
}
YY_BREAK
case 47:
YY_RULE_SETUP
#line 533 "ncgen.l"
#line 537 "ncgen.l"
{/* final */
BEGIN(INITIAL);
break;
}
YY_BREAK
case YY_STATE_EOF(ST_C_COMMENT):
#line 538 "ncgen.l"
#line 542 "ncgen.l"
{/* final, error */
fprintf(stderr,"unterminated /**/ comment");
BEGIN(INITIAL);
@ -2143,17 +2147,17 @@ case YY_STATE_EOF(ST_C_COMMENT):
YY_BREAK
case 48:
YY_RULE_SETUP
#line 544 "ncgen.l"
#line 548 "ncgen.l"
{/* Note: this next rule will not work for UTF8 characters */
return lexdebug(ncgtext[0]) ;
}
YY_BREAK
case 49:
YY_RULE_SETUP
#line 547 "ncgen.l"
#line 551 "ncgen.l"
ECHO;
YY_BREAK
#line 2157 "lex.ncg.c"
#line 2161 "lex.ncg.c"
case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(TEXT):
yyterminate();
@ -3152,7 +3156,7 @@ void ncgfree (void * ptr )
#define YYTABLES_NAME "yytables"
#line 547 "ncgen.l"
#line 551 "ncgen.l"
static int
@ -3169,7 +3173,7 @@ int
lex_init(void)
{
lineno = 1;
lextext = NULL;
lextext = bbNew();
if(0) unput(0); /* keep -Wall quiet */
return 0;
}

View File

@ -7,29 +7,19 @@
#include "includes.h"
#include "nciter.h"
#undef DOCHUNK
#define CHECK(stat,f) if(stat != NC_NOERR) {check(stat,#f,__FILE__,__LINE__);} else {}
/* forward declarations */
static int nc_blkio_init(size_t bufsize, size_t value_size, int rank,
const size_t *dims, int chunked, size_t *chunksizes,
nciter_t *iter);
const size_t *dims, nciter_t *iter);
static int up_start(int ndims, const size_t *dims, int incdim, size_t inc,
size_t* odom);
#ifdef DOCHUNK
static int up_start_by_chunks(int ndims, const size_t *dims,
const size_t *chunks, size_t* odom);
#endif
static int nciter_ndims(Symbol*,int*);
static int nciter_dimlens(Symbol*,size_t*);
static int nciter_vartype(Symbol*,Symbol**);
static int nciter_valuesize(Symbol*,size_t*);
#ifdef DOCHUNK
static int nciter_contiguous(Symbol*,int*); /* always returns contiguous */
static int nciter_chunking(Symbol*,int,size_t*); /* no-op */
#endif
static void
check(int err, const char* fcn, const char* file, const int line)
@ -54,10 +44,8 @@ nc_get_iter(Symbol* vsym,
size_t value_size; /* size in bytes of each variable element */
int ndims; /* number of dimensions for variable */
size_t dimsizes[NC_MAX_VAR_DIMS]; /* variable dimension sizes */
size_t chunksizes[NC_MAX_VAR_DIMS]; /* corresponding chunk sizes */
long long nvalues = 1;
int dim;
int chunked = 0;
memset((void*)iterp,0,sizeof(nciter_t)); /* make sure it is initialized */
@ -73,26 +61,7 @@ nc_get_iter(Symbol* vsym,
CHECK(stat, nciter_vartype);
stat = nciter_valuesize(vartype,&value_size);
CHECK(stat, nciter_valuesize);
#ifdef USE_NETCDF4
#ifdef DOCHUNK
{
int contig = 1;
if(ndims > 0) {
stat = nc_inq_var_chunking(ncid, varid, &contig, NULL);
CHECK(stat, nc_inq_var_chunking);
}
if(contig == 0) { /* chunked */
stat = nc_inq_var_chunking(ncid, varid, &contig, chunksizes);
CHECK(stat, nc_inq_var_chunking);
chunked = 1;
}
}
#else
chunked = 0;
#endif
#endif /* USE_NETCDF4 */
stat = nc_blkio_init(bufsize, value_size, ndims, dimsizes,
chunked, chunksizes, iterp);
stat = nc_blkio_init(bufsize, value_size, ndims, dimsizes, iterp);
CHECK(stat, nc_blkio_init);
iterp->to_get = 0;
return stat;
@ -114,59 +83,34 @@ nc_next_iter(nciter_t *iter, /* returned opaque iteration state */
size_t *count /* returned count vector for next vara call */
) {
int i;
/* Note: special case for chunked variables is just an
* optimization, the contiguous code below is OK even
* for chunked variables, but in general will do more I/O ... */
if(iter->first) {
if(!iter->chunked) { /* contiguous storage */
for(i = 0; i < iter->right_dim; i++) {
start[i] = 0;
count[i] = 1;
}
start[iter->right_dim] = 0;
count[iter->right_dim] = iter->rows;
for(i = iter->right_dim + 1; i < iter->rank; i++) {
start[i] = 0;
count[i] = iter->dimsizes[i];
}
} else { /* chunked storage */
#ifdef DOCHUNK
for(i = 0; i < iter->rank; i++) {
start[i] = 0;
count[i] = iter->chunksizes[i];
}
#endif
}
iter->first = 0;
for(i = 0; i < iter->right_dim; i++) {
start[i] = 0;
count[i] = 1;
}
start[iter->right_dim] = 0;
count[iter->right_dim] = iter->rows;
for(i = iter->right_dim + 1; i < iter->rank; i++) {
start[i] = 0;
count[i] = iter->dimsizes[i];
}
iter->first = 0;
} else {
if(!iter->chunked) { /* contiguous storage */
iter->more = up_start(iter->rank, iter->dimsizes, iter->right_dim,
iter->inc, start);
/* iterate on pieces of variable */
if(iter->cur < iter->numrows) {
iter->inc = iter->rows;
count[iter->right_dim] = iter->rows;
iter->cur++;
} else {
if(iter->leftover > 0) {
count[iter->right_dim] = iter->leftover;
iter->inc = iter->leftover;
iter->cur = 0;
}
}
} else { /* chunked storage */
#ifdef DOCHUNK
iter->more = up_start_by_chunks(iter->rank, iter->dimsizes,
iter->chunksizes, start);
/* adjust count to stay in range of dimsizes */
for(i = 0; i < iter->rank; i++) {
int leftover = iter->dimsizes[i] - start[i];
count[i] = iter->chunksizes[i];
if(leftover < count[i])
count[i] = leftover;
}
#endif
}
iter->more = up_start(iter->rank, iter->dimsizes, iter->right_dim,
iter->inc, start);
/* iterate on pieces of variable */
if(iter->cur < iter->numrows) {
iter->inc = iter->rows;
count[iter->right_dim] = iter->rows;
iter->cur++;
} else {
if(iter->leftover > 0) {
count[iter->right_dim] = iter->leftover;
iter->inc = iter->leftover;
iter->cur = 0;
}
}
}
iter->to_get = 1;
for(i = 0; i < iter->rank; i++) {
@ -177,16 +121,13 @@ nc_next_iter(nciter_t *iter, /* returned opaque iteration state */
/* Initialize block iteration for variables, including those that
* won't fit in the copy buffer all at once. Returns error if
* variable is chunked but size of chunks is too big to fit in bufsize
* bytes. */
* won't fit in the copy buffer all at once.
*/
static int
nc_blkio_init(size_t bufsize, /* size in bytes of in-memory copy buffer */
size_t value_size, /* size in bytes of each variable element */
int rank, /* number of dimensions for variable */
const size_t *dims, /* variable dimension sizes */
int chunked, /* 1 if variable is chunked, 0 otherwise */
size_t *chunksizes, /* if chunked, variable chunk sizes */
nciter_t *iter /* returned iteration state, don't mess with it */
) {
int stat = NC_NOERR;
@ -196,45 +137,30 @@ nc_blkio_init(size_t bufsize, /* size in bytes of in-memory copy buffer */
iter->rank = rank;
iter->first = 1;
iter->more = 1;
iter->chunked = chunked;
for(i = 0; i < rank; i++)
iter->dimsizes[i] = dims[i];
prod = value_size;
if(iter->chunked == 0) { /* contiguous */
iter->right_dim = rank - 1;
for(i = rank; i > 0; i--) {
if(prod*dims[i-1] <= bufsize) {
prod *= dims[i-1];
iter->right_dim--;
} else {
break;
}
}
if (i > 0) { /* variable won't fit in bufsize bytes */
iter->rows = bufsize/prod;
iter->numrows = dims[iter->right_dim] / iter->rows;
iter->leftover = dims[iter->right_dim] - iter->numrows * iter->rows;
iter->cur = 1;
iter->inc = iter->rows;
return stat;
}
/* else, variable will fit in bufsize bytes of memory. */
iter->right_dim = 0;
iter->rows = dims[0];
iter->inc = 0;
return stat;
}
#ifdef DOCHUNK
/* else, handle chunked case */
for(i = 0; i < rank; i++) {
iter->chunksizes[i] = chunksizes[i];
prod *= chunksizes[i];
iter->right_dim = rank - 1;
for(i = rank; i > 0; i--) {
if(prod*dims[i-1] <= bufsize) {
prod *= dims[i-1];
iter->right_dim--;
} else {
break;
}
}
if(prod > bufsize) {
stat = NC_ENOMEM;
fprintf(stderr, "chunksize (= %ld) > copy_buffer size (= %ld)\n", prod, bufsize);
if (i > 0) { /* variable won't fit in bufsize bytes */
iter->rows = bufsize/prod;
iter->numrows = dims[iter->right_dim] / iter->rows;
iter->leftover = dims[iter->right_dim] - iter->numrows * iter->rows;
iter->cur = 1;
iter->inc = iter->rows;
return stat;
}
#endif
/* else, variable will fit in bufsize bytes of memory. */
iter->right_dim = 0;
iter->rows = dims[0];
iter->inc = 0;
return stat;
}
@ -269,36 +195,6 @@ up_start(
return ret;
}
#ifdef DOCHUNK
/*
* Updates a vector of size_t, odometer style, for chunk access.
* Returns 0 if odometer overflowed, else 1.
*/
static int
up_start_by_chunks(
int ndims, /* Number of dimensions */
const size_t *dims, /* The "odometer" limits for each dimension */
const size_t *chunks, /* the odometer increments for each dimension */
size_t* odom /* The "odometer" vector to be updated */
)
{
int incdim = ndims - 1;
int id;
int ret = 1;
odom[incdim] += chunks[incdim];
for (id = incdim; id > 0; id--) {
if(odom[id] >= dims[id]) {
odom[id-1] += chunks[id-1];
/* odom[id] -= dims[id]; */
odom[id] = 0;
}
}
if (odom[0] >= dims[0])
ret = 0;
return ret;
}
#endif
static int
nciter_ndims(Symbol* sym, int* ndimsp)
@ -314,7 +210,7 @@ nciter_dimlens(Symbol* sym, size_t* dimlens)
int ndims = sym->typ.dimset.ndims;
for(i=0;i<ndims;i++) {
Symbol* dim = sym->typ.dimset.dimsyms[i];
dimlens[i] = MAX(dim->dim.declsize,dim->dim.unlimitedsize);
dimlens[i] = dim->dim.declsize;
}
return NC_NOERR;
}
@ -338,20 +234,3 @@ nciter_valuesize(Symbol* tsym, size_t* valuesizep)
*valuesizep = 1;
return NC_NOERR;
}
#ifdef DOCHUNK
static int
nciter_contiguous(Symbol* sym, int* iscontiguous)
{
if(iscontiguous != NULL)
*iscontiguous = 1; /* always returns contiguous */
return NC_NOERR;
}
static int
nciter_chunking(Symbol* sym, int contig, size_t* sizep)
{
return NC_NOERR; /* no-op */
}
#endif

View File

@ -28,9 +28,7 @@ typedef struct {
size_t to_get; /* number of values to get on this access */
int rank; /* number of dimensions */
size_t inc; /* increment for right_dim element of start vector */
int chunked; /* 1 if chunked, 0 if contiguous */
size_t dimsizes[NC_MAX_VAR_DIMS];
size_t chunksizes[NC_MAX_VAR_DIMS]; /* ignored if not chunked */
} nciter_t;
/*

View File

@ -11,31 +11,45 @@
/**************************************************/
/* Define methods for a dimension odometer*/
static void
initodometer(Odometer* odom, Dimset* dimset, size_t* startp, size_t* countp)
Odometer*
newodometer(Dimset* dimset, size_t* startp, size_t* countp)
{
int i;
odom->rank = (dimset==NULL?0:dimset->ndims);
Odometer* odom;
ASSERT(dimset != NULL);
ASSERT(dimset->ndims > 0);
odom = (Odometer*)emalloc(sizeof(Odometer));
if(odom == NULL) return NULL;
odom->origin = odom;
odom->offset = 0;
odom->rank = dimset->ndims;
ASSERT(odom->rank <= NC_MAX_VAR_DIMS);
for(i=0;i<odom->rank;i++) {
odom->declsize[i] = dimset->dimsyms[i]->dim.declsize;
odom->unlimitedsize[i] = dimset->dimsyms[i]->dim.unlimitedsize;
odom->start[i] = 0;
odom->count[i] = odom->declsize[i];
if(odom->unlimitedsize[i] > 0)odom->count[i] = odom->unlimitedsize[i];
if(startp != NULL) {
odom->start[i] = startp[i];
odom->count[i] = countp[i];
}
odom->start[i] = (startp == NULL ? 0
: startp[i]);
odom->count[i] = (countp == NULL ? odom->declsize[i]
: countp[i]);
odom->index[i] = odom->start[i];
/* verify */
ASSERT(odom->start[i] + odom->count[i] <= odom->declsize[i]);
}
return odom;
}
Odometer*
newodometer(Dimset* dimset, size_t* start, size_t* count)
newsubodometer(Odometer* origin, Dimset* dimset, int start, int stop)
{
Odometer* odom = (Odometer*)emalloc(sizeof(Odometer));
initodometer(odom,dimset,start,count);
Odometer* odom;
ASSERT(dimset != NULL);
ASSERT(dimset->ndims > 0 && dimset->ndims >= stop);
ASSERT(stop > start);
odom = (Odometer*)emalloc(sizeof(Odometer));
if(odom == NULL) return NULL;
odom->origin = origin;
odom->offset = start;
odom->rank = (stop - start);
ASSERT(odom->rank <= NC_MAX_VAR_DIMS);
return odom;
}
@ -52,13 +66,16 @@ odometerprint(Odometer* odom)
static char line[1024];
char tmp[64];
line[0] = '\0';
if(odom->rank == 0) {
if(odom->origin->rank == 0) {
strcat(line,"[]");
} else for(i=0;i<odom->rank;i++) {
sprintf(tmp,"[%lu..(%lu/%lu)]",
odom->index[i],
odom->unlimitedsize[i],
odom->declsize[i]);
int ioffset = i + odom->offset;
sprintf(tmp,"[%lu/%lu..%lu:%lu]",
odom->origin->index[ioffset],
odom->origin->start[ioffset],
odom->origin->declsize[ioffset],
odom->origin->count[ioffset]
);
strcat(line,tmp);
}
return line;
@ -67,10 +84,38 @@ odometerprint(Odometer* odom)
int
odometermore(Odometer* odom)
{
return (odom->rank > 0
&& odom->index[0] < (odom->start[0]+odom->count[0]));
size_t index,start,count;
int offset = odom->offset;
ASSERT(odom->rank > 0);
index = odom->origin->index[offset];
start = odom->origin->start[offset];
count = odom->origin->count[offset];
if(index < start + count) return 1;
/* reset the zero'th wheel before returning */
odom->origin->index[offset] = odom->origin->start[offset];
return 0;
}
int
odometerincr(Odometer* odom)
{
int i;
int last = odom->rank-1;
ASSERT(odom->rank > 0);
for(i=last;i>=0;i--) {
int ioffset = i+odom->offset;
odom->origin->index[ioffset]++;
if(odom->origin->index[ioffset]
< (odom->origin->start[ioffset]
+odom->origin->count[ioffset]))
break;
if(i==0) break; /* leave 0'th for next more() check */
odom->origin->index[ioffset] = odom->origin->start[ioffset];
}
return i; /* return rightmost incremented */
}
/*
Suppose we have the declaration int F[2][5][3];
There are obviously a total of 2 X 5 X 3 = 30 integers in F.
@ -80,85 +125,15 @@ A particular point in the three dimensions, say [x][y][z], is reduced to
a number in the range 0..29 by computing ((x*5)+y)*3+z
*/
unsigned long
odometercount(Odometer* odom)
size_t
odometeroffset(Odometer* odom)
{
int i;
unsigned long count = 0;
size_t count = 0;
for(i=0;i<odom->rank;i++) {
if(i > 0) count *= odom->count[i];
count += odom->index[i];
int ioffset = i+odom->offset;
if(i > 0) count *= odom->origin->declsize[ioffset];
count += odom->origin->index[ioffset];
}
return count;
}
void
odometerreset(Odometer* odom)
{
int rank = odom->rank;
while(rank-- > 0) {odom->index[rank] = odom->start[rank];}
}
/*
Given an odometer compute the total
number of values it would return starting at a
given wheel position; unlimited dimensions
are treated as having size 0;
*/
size_t
odometertotal(Odometer* odom, int wheel)
{
int i;
unsigned long count = 1;
for(i=wheel;i<odom->rank;i++) {
count *= odom->count[i];
}
return count;
}
int
odometerincr(Odometer* odom)
{
int i;
int last = odom->rank-1;
ASSERT(odom->rank > 0);
for(i=last;i>=0;i--) {
odom->index[i]++;
if(odom->index[i] < (odom->start[i]+odom->count[i])) break;
if(i == 0) break; /* leave the 0th entry if it overflows*/
odom->index[i] = odom->start[i];
}
return i; /* return rightmost incremented */
}
/* compute the total n-dimensional size as 1 long array;
stop if we encounter an unlimited dimension
*/
size_t
odomsubarray(Odometer* odom, int index)
{
size_t result = 1;
int i;
for(i=index;i<odom->rank;i++) {
/* treat unlimited as having size 1 because it will be a sublist */
if(odom->declsize[i] == 0) break; /*unlimited*/
result *= odom->declsize[i];
}
return result;
}
/* compute the total offset represented by the current wheel
positions for indices 0 .. index.
*/
size_t
odomprefixcount(Odometer* odom, int index)
{
size_t result = 1;
int i;
for(i=0;i<=index;i++) {
result *= odom->count[i];
}
return result;
}

View File

@ -2,36 +2,42 @@
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
/* $Id: odom.h,v 1.5 2010/05/27 21:34:18 dmh Exp $ */
/* $Header: /upc/share/CVS/netcdf-3/ncgen/odom.h,v 1.5 2010/05/27 21:34:18 dmh Exp $ */
#ifndef ODOM_H
#define ODOM_H 1
typedef struct Odometer {
int rank;
int wholepoint; /*point where whole dimensions are being used; -1=>none*/
size_t index[NC_MAX_VAR_DIMS];
size_t start[NC_MAX_VAR_DIMS];
size_t count[NC_MAX_VAR_DIMS];
size_t unlimitedsize[NC_MAX_VAR_DIMS];
size_t declsize[NC_MAX_VAR_DIMS]; /* 0 => unlimited */
int offset;
struct Odometer* origin;
size_t start[NC_MAX_VAR_DIMS];
size_t count[NC_MAX_VAR_DIMS];
size_t index[NC_MAX_VAR_DIMS];
size_t declsize[NC_MAX_VAR_DIMS];
} Odometer;
struct Dimset; /* forward */
/*Forward*/
struct Dimset;
/* Odometer operators*/
extern Odometer* newodometer(struct Dimset*, size_t* startp, size_t* countp);
extern Odometer* newsubodometer(Odometer*, struct Dimset*, int, int);
extern Odometer* newsubodometer(Odometer*, struct Dimset*,
int start, int stop);
extern void odometerfree(Odometer*);
extern char* odometerprint(Odometer* odom);
extern int odomupdate(Odometer*, size_t* startp, size_t* countp);
extern int odometermore(Odometer* odom);
extern int odometerincr(Odometer* odo);
extern unsigned long odometercount(Odometer* odo);
extern size_t odometeroffset(Odometer* odom);
#ifdef NOTUSED
extern void odometerreset(Odometer*);
extern size_t odometertotal(Odometer*,int);
extern size_t odomsubarray(Odometer* odom, int index);
extern size_t odomprefixcount(Odometer* odom, int index);
#endif
#endif /*ODOM_H*/

View File

@ -17,25 +17,13 @@ static void processtypesizes(void);
static void processvars(void);
static void processattributes(void);
static void processspecials(void);
static void processdatalists(void);
static void processdatalist(Symbol*);
static void processunlimiteddims(void);
static void inferattributetype(Symbol* asym);
static void checkconsistency(void);
static void validate(void);
static int tagvlentypes(Symbol* tsym);
static void walkdata(Symbol*);
static void walkarray(Symbol*, Datasrc*, int, Datalist*);
static void walktype(Symbol*, Datasrc*, Datalist*);
static void walkfieldarray(Symbol*, Datasrc*, Dimset*, int);
static void walkchararray(Symbol*,Datalist*);
static void walkchararrayr(Dimset* dimset, Datalist** datap, int lastunlim, int index, int fillchar);
static void walkcharfieldarray(Constant*, Dimset*, Datalist*);
static void walkcharvlen(Constant*);
static Symbol* uniquetreelocate(Symbol* refsym, Symbol* root);
List* vlenconstants; /* List<Constant*>;*/
@ -61,8 +49,8 @@ processsemantics(void)
processattributes();
/* Fix up enum constant values*/
processenums();
/* Fix up datalists*/
processdatalists();
/* Compute the unlimited dimension sizes */
processunlimiteddims();
/* check internal consistency*/
checkconsistency();
/* do any needed additional semantic checks*/
@ -422,10 +410,10 @@ computesize(Symbol* tsym)
}
tsym->typ.size = offset;
break;
case NC_FIELD: /* Compute size of all non-unlimited dimensions*/
case NC_FIELD: /* Compute size assume no unlimited dimensions*/
if(tsym->typ.dimset.ndims > 0) {
computesize(tsym->typ.basetype);
totaldimsize = arraylength(&tsym->typ.dimset);
totaldimsize = crossproduct(&tsym->typ.dimset,0,0);
tsym->typ.size = tsym->typ.basetype->typ.size * totaldimsize;
tsym->typ.alignment = tsym->typ.basetype->typ.alignment;
tsym->typ.nelems = 1;
@ -577,7 +565,6 @@ static void
processspecials(void)
{
int i;
if(allowspecial) return; /* Only dump attributes if using netcdf-3 */
for(i=0;i<listlength(vardefs);i++) {
Symbol* vsym = (Symbol*)listget(vardefs,i);
processspecial1(vsym);
@ -594,7 +581,9 @@ processattributes(void)
/* If the attribute has a zero length, then default it */
if(asym->data == NULL || asym->data->length == 0) {
asym->data = builddatalist(1);
#ifdef IGNORE
dlappend(asym->data,NULL);
#endif
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
/* force type to be NC_CHAR */
asym->typ.basetype = primsymbols[NC_CHAR];
@ -609,12 +598,29 @@ processattributes(void)
/* If the attribute has a zero length, then default it */
if(asym->data == NULL || asym->data->length == 0) {
asym->data = builddatalist(1);
#ifdef IGNORE
dlappend(asym->data,NULL);
#endif
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
/* force type to be NC_CHAR */
asym->typ.basetype = primsymbols[NC_CHAR];
}
if(asym->typ.basetype == NULL) inferattributetype(asym);
/* If no basetype is specified, then try to infer it;
the exception if _Fillvalue, whose type is that of the
containing variable.
*/
if(strcmp(asym->name,specialname(_FILLVALUE_FLAG)) == 0) {
/* This is _Fillvalue */
asym->typ.basetype = asym->att.var->typ.basetype; /* its basetype is same as its var*/
/* put the datalist into the specials structure */
if(asym->data == NULL) {
/* Generate a default fill value */
asym->data = getfiller(asym->typ.basetype);
}
asym->att.var->var.special._Fillvalue = asym->data;
} else if(asym->typ.basetype == NULL) {
inferattributetype(asym);
}
/* fill in the typecode*/
asym->typ.typecode = asym->typ.basetype->typ.typecode;
}
@ -746,21 +752,6 @@ lookup(nc_class objectclass, Symbol* pattern)
return lookupingroup(objectclass,pattern->name,grp);
}
#ifndef NO_STDARG
void
semerror(const int lno, const char *fmt, ...)
#else
void
semerror(lno,fmt,va_alist) const int lno; const char* fmt; va_dcl
#endif
{
va_list argv;
vastart(argv,fmt);
(void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lno);
vderror(fmt,argv);
exit(1);
}
/* return internal size for values of specified netCDF type */
size_t
@ -846,494 +837,112 @@ validate(void)
}
}
}
/*
Do any pre-processing of datalists.
1. Compute the effective size of unlimited
dimensions vis-a-vis this data list
2. Compute the length of attribute lists
3. Collect the VLEN constants
4. add fills as needed to get lengths correct
5. comput max of interior unlimited instances
*/
void
processdatalists(void)
static void
computeunlimitedsizes(Dimset* dimset, int dimindex, Datalist* data, int ischar)
{
int i;
if(debug > 0) fdebug("processdatalists:\n");
vlenconstants = listnew();
size_t xproduct, unlimsize;
int nextunlim,lastunlim;
Symbol* thisunlim = dimset->dimsyms[dimindex];
size_t length;
ASSERT(thisunlim->dim.isunlimited);
nextunlim = findunlimited(dimset,dimindex+1);
lastunlim = (nextunlim == dimset->ndims);
listsetalloc(vlenconstants,1024);
xproduct = crossproduct(dimset,dimindex+1,nextunlim);
/* process global attributes*/
for(i=0;i<listlength(gattdefs);i++) {
Symbol* asym = (Symbol*)listget(gattdefs,i);
if(asym->data != NULL)
processdatalist(asym);
if(debug > 0 && asym->data != NULL) {
fdebug(":%s.datalist: ",asym->name);
dumpdatalist(asym->data,"");
fdebug("\n");
if(!lastunlim) {
/*!lastunlim => data is list of sublists, recurse on each sublist*/
for(i=0;i<data->length;i++) {
Constant* con = data->data+i;
ASSERT(con->nctype == NC_COMPOUND);
computeunlimitedsizes(dimset,nextunlim,con->value.compoundv,ischar);
}
}
/* process per variable attributes*/
for(i=0;i<listlength(attdefs);i++) {
Symbol* asym = (Symbol*)listget(attdefs,i);
if(asym->data != NULL)
processdatalist(asym);
if(debug > 0 && asym->data != NULL) {
fdebug("%s:%s.datalist: ",asym->att.var->name,asym->name);
dumpdatalist(asym->data,"");
fdebug("\n");
/* Compute candiate size of this unlimited */
length = data->length;
unlimsize = length / xproduct;
if(length % xproduct != 0)
unlimsize++; /* => fill requires at some point */
#ifdef DEBUG2
fprintf(stderr,"unlimsize: dim=%s declsize=%d xproduct=%d newsize=%d\n",
thisunlim->name,thisunlim->dim.declsize,xproduct,unlimsize);
#endif
if(thisunlim->dim.declsize < unlimsize) /* want max length of the unlimited*/
thisunlim->dim.declsize = unlimsize;
} else {//lastunlim
if(ischar) {
/* Char case requires special computations;
compute total number of characters */
length = 0;
for(i=0;i<data->length;i++) {
Constant* con = &data->data[i];
switch (con->nctype) {
case NC_CHAR: case NC_BYTE: case NC_UBYTE:
length++;
break;
case NC_STRING:
length += con->value.stringv.len;
break;
default:
semwarn(datalistline(data),"Illegal character constant");
}
}
} else { /* Data list should be a list of simple non-char constants */
length = data->length;
}
unlimsize = length / xproduct;
if(length % xproduct != 0)
unlimsize++; /* => fill requires at some point */
#ifdef DEBUG2
fprintf(stderr,"unlimsize: dim=%s declsize=%d xproduct=%d newsize=%d\n",
thisunlim->name,thisunlim->dim.declsize,xproduct,unlimsize);
#endif
if(thisunlim->dim.declsize < unlimsize) /* want max length of the unlimited*/
thisunlim->dim.declsize = unlimsize;
}
/* process all variable data lists */
}
static void
processunlimiteddims(void)
{
int i;
/* Set all unlimited dims to size 0; */
for(i=0;i<listlength(dimdefs);i++) {
Symbol* dim = (Symbol*)listget(dimdefs,i);
if(dim->dim.isunlimited)
dim->dim.declsize = 0;
}
/* Walk all variables */
for(i=0;i<listlength(vardefs);i++) {
Symbol* vsym = (Symbol*)listget(vardefs,i);
if(vsym->data != NULL)
processdatalist(vsym);
if(debug > 0 && vsym->data != NULL) {
fdebug("%s.datalist: ",vsym->name);
dumpdatalist(vsym->data,"");
fdebug("\n");
}
}
}
static void
processdatalist(Symbol* sym)
{
walkdata(sym);
}
/*
Recursively walk the variable/basetype and
simultaneously walk the datasrc.
Uses separate code for:
1. variables
2. types
3. field arrays
This set of procedures is an example of the
canonical way to simultaneously walk a variable
and a datalist.
*/
static void
walkdata(Symbol* sym)
{
int rank = sym->typ.dimset.ndims;
size_t total = 0;
Datasrc* src = NULL;
Datalist* fillsrc = sym->var.special._Fillvalue;
int ischartype = (sym->typ.basetype->typ.typecode == NC_CHAR);
/* special case */
if(sym->objectclass == NC_VAR && ischartype && rank > 0) {
walkchararray(sym, fillsrc);
} else {
src = datalist2src(sym->data);
switch (sym->objectclass) {
case NC_VAR:
if(rank == 0) /*scalar*/
walktype(sym->typ.basetype,src,fillsrc);
else
walkarray(sym,src,0,fillsrc);
break;
case NC_ATT:
for(total=0;srcpeek(src) != NULL;total++)
walktype(sym->typ.basetype,src,NULL);
break;
default:
PANIC1("walkdata: illegal objectclass: %d",(int)sym->objectclass);
break;
}
if(src) freedatasrc(src);
}
}
/* Walk non-character arrays */
static void
walkarray(Symbol* vsym, Datasrc* src, int dimindex, Datalist* fillsrc)
{
int i;
Dimset* dimset = &vsym->typ.dimset;
int rank = dimset->ndims;
int lastdim = (dimindex == (rank-1));
int firstdim = (dimindex == 0);
Symbol* dim = dimset->dimsyms[dimindex];
int isunlimited = (dim->dim.declsize == NC_UNLIMITED);
size_t count = 0;
ASSERT(rank > 0);
ASSERT(vsym->typ.basetype->typ.typecode != NC_CHAR);
if(isunlimited) {
int pushed = 0;
if(!firstdim) {
if(!issublist(src))
semerror(srcline(src),"Expected {..} found primitive");
srcpush(src);
pushed = 1;
}
for(count=0;srcpeek(src) != NULL;count++) {
if(lastdim)
walktype(vsym->typ.basetype,src,fillsrc);
else
walkarray(vsym,src,dimindex+1,fillsrc);
}
/* compute unlimited max */
dim->dim.unlimitedsize = MAX(count,dim->dim.unlimitedsize);
if(pushed) srcpop(src);
} else { /* !ischartype && !isunlimited */
count = dim->dim.declsize;
for(i=0;i<dim->dim.declsize;i++) {
if(lastdim)
walktype(vsym->typ.basetype,src,fillsrc);
else
walkarray(vsym,src,dimindex+1,fillsrc);
}
}
}
static void
walktype(Symbol* tsym, Datasrc* src, Datalist* fillsrc)
{
int i;
int count;
Constant* con;
Datalist* dl;
ASSERT(tsym->objectclass == NC_TYPE);
switch (tsym->subclass) {
case NC_ENUM: case NC_OPAQUE: case NC_PRIM:
srcnext(src);
break;
case NC_COMPOUND:
if(!isfillvalue(src) && !issublist(src)) {/* fail on no compound*/
semerror(srcline(src),"Compound constants must be enclosed in {..}");
}
con = srcnext(src);
if(con == NULL || con->nctype == NC_FILLVALUE) {
dl = getfiller(tsym,fillsrc);
ASSERT(dl->length == 1);
con = &dl->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(srcline(src),"Vlen fill constants must be enclosed in {..}");
Symbol* var = (Symbol*)listget(vardefs,i);
int first,ischar;
Dimset* dimset = &var->typ.dimset;
if(dimset->ndims == 0) continue; /* ignore scalars */
if(var->data == NULL) continue; /* no data list to walk */
ischar = (var->typ.basetype->typ.typecode == NC_CHAR);
first = findunlimited(dimset,0);
if(first == dimset->ndims) continue; /* no unlimited dims */
if(first == 0) {
computeunlimitedsizes(dimset,first,var->data,ischar);
} else {
for(i=0;i<var->data->length;i++) {
Constant* con = var->data->data+i;
ASSERT(con->nctype == NC_COMPOUND);
computeunlimitedsizes(dimset,first,con->value.compoundv,ischar);
}
}
dl = con->value.compoundv;
srcpushlist(src,dl); /* enter the sublist*/
for(count=0,i=0;i<listlength(tsym->subnodes) && srcmore(src);i++,count++) {
Symbol* field = (Symbol*)listget(tsym->subnodes,i);
walktype(field,src,NULL);
}
srcpop(src);
break;
case NC_VLEN:
if(!isfillvalue(src) && !issublist(src)) {/* fail on no compound*/
semerror(srcline(src),"Vlen constants must be enclosed in {..}");
}
con = srcnext(src);
if(con == NULL || con->nctype == NC_FILLVALUE) {
dl = getfiller(tsym,fillsrc);
ASSERT(dl->length == 1);
con = &dl->data[0];
if(con->nctype != NC_COMPOUND) {
semerror(srcline(src),"Vlen fill constants must be enclosed in {..}");
}
}
if(!listcontains(vlenconstants,(elem_t)con)) {
dl = con->value.compoundv;
/* Process list only if new */
srcpushlist(src,dl); /* enter the sublist*/
if(tsym->typ.basetype->typ.typecode == NC_CHAR) {
walkcharvlen(con);
} else for(count = 0;srcmore(src);count++) {
walktype(tsym->typ.basetype,src,NULL);
}
srcpop(src);
dl->vlen.count = count;
dl->vlen.uid = listlength(vlenconstants);
dl->vlen.schema = tsym;
listpush(vlenconstants,(elem_t)con);
}
break;
case NC_FIELD:
if(tsym->typ.dimset.ndims > 0) {
if(tsym->typ.basetype->typ.typecode == NC_CHAR) {
Constant* con = srcnext(src);
walkcharfieldarray(con,&tsym->typ.dimset,fillsrc);
} else
walkfieldarray(tsym->typ.basetype,src,&tsym->typ.dimset,0);
} else
walktype(tsym->typ.basetype,src,NULL);
break;
default: PANIC1("processdatalist: unexpected subclass %d",tsym->subclass);
}
}
/* Used only for structure field arrays*/
static void
walkfieldarray(Symbol* basetype, Datasrc* src, Dimset* dimset, int index)
{
int i;
int rank = dimset->ndims;
int lastdim = (index == (rank-1));
Symbol* dim = dimset->dimsyms[index];
size_t datasize = dim->dim.declsize;
ASSERT(datasize != 0);
for(i=0;i<datasize;i++) {
if(lastdim)
walktype(basetype,src,NULL);
else
walkfieldarray(basetype,src,dimset,index+1);
#ifdef DEBUG1
/* print unlimited dim size */
if(listlength(dimdefs) == 0)
fprintf(stderr,"unlimited: no unlimited dimensions\n");
else for(i=0;i<listlength(dimdefs);i++) {
Symbol* dim = (Symbol*)listget(dimdefs,i);
if(dim->dim.isunlimited)
fprintf(stderr,"unlimited: %s = %lu\n",
dim->name,
(unsigned long)dim->dim.declsize);
}
}
/* Return 1 if the set of dimensions from..rank-1 are not unlimited */
int
nounlimited(Dimset* dimset, int from)
{
int index;
index = lastunlimited(dimset);
return (index <= from ? 1: 0);
}
/* Return index of the rightmost unlimited dimension; -1 => no unlimiteds */
int
lastunlimited(Dimset* dimset)
{
int i,index;
for(index=-1,i=0;i<dimset->ndims;i++) {
Symbol* dim = dimset->dimsyms[i];
if(dim->dim.declsize == NC_UNLIMITED) index = i;
}
return index;
}
/* Field is an array and basetype is character.
The constant should be of the form { <stringable>, <stringable>...}.
Make each stringable be a multiple of the size of the last
dimension of the field array. Then concat all of them
together into one long string. Then pad that string to be
as long as the product of the array dimensions. Finally,
modify the constant to hold that long string.
*/
static void
walkcharfieldarray(Constant* con, Dimset* dimset, Datalist* fillsrc)
{
int rank = dimset->ndims;
Symbol* lastdim = dimset->dimsyms[rank-1];
size_t lastdimsize = lastdim->dim.declsize;
size_t slabsize = subarraylength(dimset,0);
int fillchar = getfillchar(fillsrc);
Datalist* data;
Constant newcon;
/* By data constant rules, con should be a compound object */
if(con->nctype != NC_COMPOUND) {
semerror(con->lineno,"Malformed character field array");
return;
}
data = con->value.compoundv;
/* canonicalize the strings in con and then pad to slabsize */
if(!buildcanonicalcharlist(data,lastdimsize,fillchar,&newcon))
return;
/* pad to slabsize */
padstring(&newcon,slabsize,fillchar);
/* Now, since we have a compound containing a single string,
optimize by replacing the compound with the string.
*/
*con = newcon;
}
/* Vsym is an array variable whose basetype is character.
The vsym->data list should be a set of strings
possibly enclosed in one or more nested sets of braces.
{<stringlist>}, {<stringlist>}...
There are several cases to consider.
1. the variable's dimension set has no unlimiteds
Actions:
1. for each stringable in the data list,
pad it up to a multiple of the size of the
last dimension.
2. concat all of the stringables
3. pad the concat to the size of the product of
the dimension sizes.
2. the dimension set has one or more unlimiteds.
This means that we have to recursively deal with
nested compound instances.
The last (rightmost) unlimited will correspond
to a sequence of stringables.
This has two special subcases
2a. the last dimension IS NOT unlimited
Actions:
1. for each stringable in the data list,
pad it up to a multiple of the size of the
last dimension.
2. concat all of the stringables
3. Use the length of the concat plus the
product of the dimensions from just
after the last unlimited to the last dimension
to inform the size of the unlimited.
2b. the last dimension IS unlimited
Actions:
1. concat all of the stringables with no padding
2. Use the length of the concat to inform the size
of the unlimited.
Each unlimited dimension to the left of the last unlimited
will introduce another nesting of braces.
3. For each dimension to the left of the last
unlimited, there are two cases.
3a. dimension is NOT unlimited
ACTION:
1. The set of items from the right are padded to
the length of the dimension size
3b. dimension IS unlimited
ACTION:
1. no action
Finally, modify the variable's data list to contain these
modified stringlists.
*/
static void
walkchararray(Symbol* vsym, Datalist* fillsrc)
{
Dimset* dimset = &vsym->typ.dimset;
int lastunlimindex;
int rank = dimset->ndims;
Symbol* lastdim = dimset->dimsyms[rank-1];
size_t lastdimsize = lastdim->dim.declsize;
Constant newcon = nullconstant;
int fillchar = getfillchar(fillsrc);
lastunlimindex = lastunlimited(dimset);
#ifdef IGNORE
simpleunlim = (lastunlimindex == 0);
#endif
/* If the unlimited is also the last dimension, then do no padding */
if(lastdimsize == 0) lastdimsize = 1;
if(lastunlimindex < 0) {
/* If it turns out that there are no unlimiteds, then canonicalize
the string and then pad to the dim product
*/
size_t slabsize = arraylength(dimset);
/* If rank is 1, then dont' pad the string */
if(rank == 1) lastdimsize = 1;
if(!buildcanonicalcharlist(vsym->data,lastdimsize,fillchar,&newcon))
return;
/* pad to slabsize */
padstring(&newcon,slabsize,fillchar);
/* replace vsym->data */
vsym->data = const2list(&newcon);
#ifdef IGNORE
} else if(simpleunlim) {
/* First dimension is the only unlimited */
/* canonicalize but do not attempt to pad because
we do not yet know the final size of the unlimited dimension
*/
size_t count, subslabsize;
Symbol* dim0 = dimset->dimsyms[0];
ASSERT(dim0->dim.declsize == NC_UNLIMITED);
if(!buildcanonicalcharlist(vsym->data,lastdimsize,fillchar,&newcon))
return;
/* track consistency with the unlimited dimension */
/* Compute the size of the subslab below this dimension */
subslabsize = subarraylength(dimset,lastunlimindex+1);
/* divide stringv.len by subslabsize and use as the unlim count*/
count = newcon.value.stringv.len / subslabsize;
dim0->dim.unlimitedsize = MAX(count,dim0->dim.unlimitedsize);
/* replace vsym->data */
vsym->data = const2list(&newcon);
#endif
} else {/* 1 or more unlimiteds */
walkchararrayr(&vsym->typ.dimset, &vsym->data, lastunlimindex, 0, fillchar);
}
}
/* Handle case 3:
this will recursively walk down the
compound nesting to apply actions.
*/
static void
walkchararrayr(Dimset* dimset, Datalist** datap, int lastunlimited, int index, int fillchar)
{
int i;
Symbol* dim = dimset->dimsyms[index];
int rank = dimset->ndims;
int isunlimited = (dim->dim.declsize == NC_UNLIMITED);
Datalist* data = *datap;
/* Split on islastunlimited or not */
if(index == lastunlimited) {
size_t subslabsize,count;
Symbol* lastdim = dimset->dimsyms[rank-1];
size_t lastdimsize = (lastdim->dim.declsize==NC_UNLIMITED?1:lastdim->dim.declsize);
Constant newcon = nullconstant;
/* The datalist should contain just stringables; concat them with padding */
if(!buildcanonicalcharlist(data,lastdimsize,fillchar,&newcon))
return;
/* track consistency with the unlimited dimension */
/* Compute the size of the subslab below this dimension */
subslabsize = subarraylength(dimset,index+1);
/* divide stringv.len by subslabsize and use as the unlim count*/
count = newcon.value.stringv.len / subslabsize;
dim->dim.unlimitedsize = MAX(count,dim->dim.unlimitedsize);
/* replace parent compound */
*datap = const2list(&newcon);
} else {/* dimension to left of last unlimited */
/* data should be a set of compounds */
size_t expected = (isunlimited ? data->length : dim->dim.declsize );
for(i=0;i<expected;i++) {
Constant* con;
if(i >= data->length) {/* extend data */
Constant cmpd;
emptycompoundconst(datalistline(data),&cmpd);
dlappend(data,&cmpd);
}
con = data->data+i;
if(con->nctype != NC_COMPOUND) {
semerror(datalistline(data),"Malformed Character datalist");
continue;
}
/* recurse */
walkchararrayr(dimset,&con->value.compoundv,lastunlimited,index+1,fillchar);
if(isunlimited) /* set unlim count */
dim->dim.unlimitedsize = MAX(data->length,dim->dim.unlimitedsize);
}
}
}
static void
walkcharvlen(Constant* src)
{
Datalist* data;
Constant newcon;
/* By data constant rules, src should be a compound object */
if(src->nctype != NC_COMPOUND) {
semerror(src->lineno,"Malformed character vlen");
return;
}
data = src->value.compoundv;
/* canonicalize the strings in src */
if(!buildcanonicalcharlist(data,1,NC_FILL_CHAR,&newcon))
return;
/* replace src */
*src = newcon;
}

View File

@ -6,6 +6,8 @@
#include "includes.h"
#define DATALISTINIT 32
/* Track primitive symbol instances (initialized in ncgen.y) */
Symbol* primsymbols[PRIMNO];
@ -488,7 +490,6 @@ dlsetalloc(Datalist* dl, size_t newalloc)
dl->data = newdata;
}
#define DATALISTINIT 256
Datalist*
builddatalist(int initial)
@ -583,30 +584,22 @@ cleanup()
reclaimSymbols();
}
/* compute the total n-dimensional size as 1 long array;
if stop == 0, then stop = dimset->ndims.
*/
size_t
arraylength(Dimset* dimset)
{
return subarraylength(dimset,0);
}
/* compute the total n-dimensional size as 1 long array*/
/* stop if we encounter an unlimited dimension */
size_t
subarraylength(Dimset* dimset, int first)
crossproduct(Dimset* dimset, int start, int stop)
{
size_t totalsize = 1;
int i,last;
last = dimset->ndims;
for(i=first;i<last;i++) {
if(dimset->dimsyms[i]->dim.declsize == NC_UNLIMITED) break;
totalsize = totalsize * MAX(dimset->dimsyms[i]->dim.unlimitedsize,
dimset->dimsyms[i]->dim.declsize);
int i;
if(stop == 0) stop = dimset->ndims;
for(i=start;i<stop;i++) {
totalsize = totalsize * dimset->dimsyms[i]->dim.declsize;
}
return totalsize;
}
/* Do the "complement" of subarray length;
/* 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
@ -614,14 +607,7 @@ subarraylength(Dimset* dimset, int first)
size_t
prefixarraylength(Dimset* dimset, int last)
{
size_t totalsize = 1;
int i;
for(i=0;i<=last;i++) {
if(dimset->dimsyms[i]->dim.declsize == NC_UNLIMITED) break;
totalsize = totalsize * MAX(dimset->dimsyms[i]->dim.unlimitedsize,
dimset->dimsyms[i]->dim.declsize);
}
return totalsize;
return crossproduct(dimset,0,last+1);
}
@ -643,3 +629,25 @@ check_err(const int stat, const int line, const char* file) {
}
}
int
findunlimited(Dimset* dimset, int start)
{
for(;start<dimset->ndims;start++) {
if(dimset->dimsyms[start]->dim.isunlimited)
return start;
}
return dimset->ndims;
}
int
findlastunlimited(Dimset* dimset)
{
int i;
for(i=dimset->ndims-1;i>=0;i--) {
if(dimset->dimsyms[i]->dim.isunlimited)
return i;
}
return -1;
}

View File

@ -42,8 +42,12 @@ extern char* poolalloc(size_t);
extern char* pooldup(char*);
extern char* poolcat(const char* s1, const char* s2);
extern size_t arraylength(Dimset* dimset);
extern size_t subarraylength(Dimset* dimset, int start);
/* compute the total n-dimensional size as 1 long array;
if stop == 0, then stop = dimset->ndims.
*/
extern size_t crossproduct(Dimset* dimset, int start, int stop);
extern int findunlimited(Dimset* dimset, int start);
extern int findlastunlimited(Dimset* dimset);
extern unsigned char* makebytestring(char* s, size_t* lenp);
extern int getpadding(int offset, int alignment);