netcdf-c/ncgen/genchar.c

277 lines
8.4 KiB
C
Raw Normal View History

2010-06-03 21:24:43 +08:00
/*********************************************************************
* Copyright 2009, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
#include "includes.h"
/******************************************************/
/* Code for generating char variables etc; mostly
language independent */
/******************************************************/
static size_t gen_charconstant(NCConstant*, Bytebuffer*, int fillchar);
static int getfillchar(Datalist* fillsrc);
static void gen_chararrayr(Dimset*,int,int,Bytebuffer*,Datalist*,int,int,int);
2010-06-03 21:24:43 +08:00
/*
Matching strings to char variables, attributes, and vlen
constants is challenging because it is desirable to mimic
2014-08-18 02:03:23 +08:00
the original ncgen(3). The "algorithms" used there have no
2010-06-03 21:24:43 +08:00
simple characterization (such as "abc" == {'a','b','c'}).
So, this rather ugly code is kept in this file
2014-08-18 02:03:23 +08:00
and a variety of heuristics are used to mimic ncgen3.
2010-06-03 21:24:43 +08:00
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.
*/
2010-06-03 21:24:43 +08:00
void
gen_chararray(Dimset* dimset, Datalist* data, Bytebuffer* databuf, Datalist* fillsrc)
2010-06-03 21:24:43 +08:00
{
int ndims,lastunlim;
int fillchar = getfillchar(fillsrc);
size_t expectedsize,xproduct;
size_t unitsize;
2010-06-03 21:24:43 +08:00
ASSERT(bbLength(databuf) == 0);
2010-06-03 21:24:43 +08:00
ndims = dimset->ndims;
2010-06-03 21:24:43 +08:00
/* 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);
2010-06-03 21:24:43 +08:00
}
/* Recursive helper */
2010-06-03 21:24:43 +08:00
static void
gen_chararrayr(Dimset* dimset, int dimindex, int lastunlimited,
Bytebuffer* databuf, Datalist* data, int fillchar,
int unitsize, int expectedsize)
2010-06-03 21:24:43 +08:00
{
int i;
size_t dimsize = dimset->dimsyms[dimindex]->dim.declsize;
if(dimindex < lastunlimited) {
/* keep recursing */
for(i=0;i<dimsize;i++) {
NCConstant* c = datalistith(data,i);
ASSERT(islistconst(c));
gen_chararrayr(dimset,dimindex+1,lastunlimited,databuf,
c->value.compoundv,fillchar,unitsize,expectedsize);
}
} else {/* we should be at a list of simple constants */
for(i=0;i<data->length;i++) {
NCConstant* 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");
2010-06-03 21:24:43 +08:00
}
}
}
/* 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);
}
2010-06-03 21:24:43 +08:00
}
}
void
gen_charattr(Datalist* data, Bytebuffer* databuf)
2010-06-03 21:24:43 +08:00
{
gen_charvlen(data,databuf);
2010-06-03 21:24:43 +08:00
}
void
gen_charvlen(Datalist* data, Bytebuffer* databuf)
2010-06-03 21:24:43 +08:00
{
int i;
NCConstant* c;
2010-06-03 21:24:43 +08:00
ASSERT(bbLength(databuf) == 0);
2010-06-03 21:24:43 +08:00
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;
2010-06-03 21:24:43 +08:00
}
}
}
static size_t
gen_charconstant(NCConstant* con, Bytebuffer* databuf, int fillchar)
2010-06-03 21:24:43 +08:00
{
/* 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;
2013-09-24 04:19:40 +08:00
bbAppendn(databuf,con->value.stringv.stringv,
con->value.stringv.len);
bbNull(databuf);
break;
case NC_FILL:
bbAppend(databuf,fillchar);
break;
default:
PANIC("unexpected constant type");
}
return constsize;
2010-06-03 21:24:43 +08:00
}
static int
getfillchar(Datalist* fillsrc)
{
/* Determine the fill char */
int fillchar = 0;
if(fillsrc != NULL && fillsrc->length > 0) {
NCConstant* ccon = fillsrc->data;
if(ccon->nctype == NC_CHAR) {
fillchar = ccon->value.charv;
} else if(ccon->nctype == NC_STRING) {
if(ccon->value.stringv.len > 0) {
fillchar = ccon->value.stringv.stringv[0];
}
}
}
if(fillchar == 0) fillchar = NC_FILL_CHAR; /* default */
return fillchar;
}
#ifndef CHARBUG
void
gen_leafchararray(Dimset* dimset, int lastunlim, Datalist* data,
Bytebuffer* databuf, Datalist* fillsrc)
{
int i;
size_t expectedsize,xproduct,unitsize;
int ndims = dimset->ndims;
int fillchar = getfillchar(fillsrc);
ASSERT(bbLength(databuf) == 0);
/* Assume dimindex is the last unlimited (or 0 if their are
no unlimiteds => we should be at a list of simple constants
*/
/* Compute crossproduct upto the last dimension,
starting at the last unlimited
*/
xproduct = crossproduct(dimset,lastunlim,ndims-1);
/* Compute the required size (after padding) of each string constant */
/* expected size is the size of concat of the string constants
after padding
*/
if(ndims == 0) {
unitsize = 1;
expectedsize = (xproduct * unitsize);
} else
if(lastunlim == ndims-1) {/* last dimension is unlimited */
unitsize = 1;
expectedsize = (xproduct*dimset->dimsyms[lastunlim]->dim.declsize);
} else
{ /* last dim is not unlimited */
unitsize = dimset->dimsyms[ndims-1]->dim.declsize;
expectedsize = (xproduct * unitsize);
}
for(i=0;i<data->length;i++) {
NCConstant* c = datalistith(data,i);
ASSERT(!islistconst(c));
if(isstringable(c->nctype)) {
int j;
size_t constsize;
constsize = gen_charconstant(c,databuf,fillchar);
if(constsize == 0 || 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);
}
}
}
#endif /*!CHARBUG*/