mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-27 07:30:33 +08:00
220 lines
5.2 KiB
C
220 lines
5.2 KiB
C
/*********************************************************************
|
|
* Copyright 2018, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
*********************************************************************/
|
|
|
|
#include "includes.h"
|
|
#include <stddef.h>
|
|
|
|
#ifdef ENABLE_C
|
|
|
|
#include <math.h>
|
|
#ifndef isnan
|
|
extern int isnan(double);
|
|
#endif
|
|
|
|
static int c_uid = 0;
|
|
|
|
static int
|
|
c_charconstant(Generator* generator, Symbol* sym, Bytebuffer* codebuf, ...)
|
|
{
|
|
/* Escapes and quoting will be handled in genc_write */
|
|
/* Just transfer charbuf to codebuf */
|
|
Bytebuffer* charbuf;
|
|
va_list ap;
|
|
va_start(ap,codebuf);
|
|
charbuf = va_arg(ap, Bytebuffer*);
|
|
va_end(ap);
|
|
bbNull(charbuf);
|
|
bbCatbuf(codebuf,charbuf);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
c_constant(Generator* generator, Symbol* sym, NCConstant* con, Bytebuffer* buf,...)
|
|
{
|
|
Bytebuffer* codetmp = bbNew();
|
|
char* special = NULL;
|
|
|
|
switch (con->nctype) {
|
|
case NC_CHAR:
|
|
if(con->value.charv == '\'')
|
|
bbprintf(codetmp,"'\\''");
|
|
else
|
|
bbprintf(codetmp,"'%s'",cescapifychar(con->value.charv,'\''));
|
|
break;
|
|
case NC_BYTE:
|
|
bbprintf(codetmp,"%hhd",con->value.int8v);
|
|
break;
|
|
case NC_SHORT:
|
|
bbprintf(codetmp,"%hd",con->value.int16v);
|
|
break;
|
|
case NC_INT:
|
|
bbprintf(codetmp,"%d",con->value.int32v);
|
|
break;
|
|
case NC_FLOAT:
|
|
/* Special case for nanf */
|
|
if(isnan(con->value.floatv))
|
|
bbprintf(codetmp,"nanf");
|
|
else
|
|
bbprintf(codetmp,"%f",con->value.floatv);
|
|
break;
|
|
case NC_DOUBLE:
|
|
/* Special case for nan */
|
|
if(isnan(con->value.doublev))
|
|
bbprintf(codetmp,"nan");
|
|
else
|
|
bbprintf(codetmp,"%lf",con->value.doublev);
|
|
break;
|
|
case NC_UBYTE:
|
|
bbprintf(codetmp,"%hhuU",con->value.uint8v);
|
|
break;
|
|
case NC_USHORT:
|
|
bbprintf(codetmp,"%huU",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,"%lluULL",con->value.uint64v);
|
|
break;
|
|
case NC_ECONST:
|
|
bbprintf(codetmp,"%s",cname(con->value.enumv));
|
|
break;
|
|
case NC_NIL:
|
|
case NC_STRING: { /* handle separately */
|
|
if(con->value.stringv.len == 0 && con->value.stringv.stringv == NULL) {
|
|
bbprintf(codetmp,"NULL");
|
|
} else {
|
|
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;
|
|
size_t bslen = 4*con->value.opaquev.len;
|
|
special = poolalloc(bslen+2+1);
|
|
strcpy(special,"\"");
|
|
p = con->value.opaquev.stringv;
|
|
while(*p) {
|
|
strlcat(special,"\\x",bslen+3);
|
|
strlcat(special,p,bslen+3);
|
|
p += 2;
|
|
}
|
|
strlcat(special,"\"",bslen+3);
|
|
} break;
|
|
|
|
default: PANIC1("ncstype: bad type code: %d",con->nctype);
|
|
|
|
}
|
|
if(special == NULL)
|
|
bbCatbuf(buf,codetmp);
|
|
else
|
|
bbCat(buf,special);
|
|
bbFree(codetmp);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
c_listbegin(Generator* generator, Symbol* sym, void* liststate, 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, Symbol* sym, void* liststate, 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, Symbol* sym, void* liststate, 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, Symbol* tsym, Bytebuffer* codebuf, int uid, size_t count, ...)
|
|
{
|
|
/* Build a bytebuffer to capture the vlen decl */
|
|
List* declstack = (List*)generator->globalstate;
|
|
Bytebuffer* decl = bbNew();
|
|
Bytebuffer* vlenbuf;
|
|
va_list ap;
|
|
va_start(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,(void*)decl);
|
|
/* Now generate the reference to buffer */
|
|
bbprintf(codebuf,"{%u,(void*)vlen_%u}",count,uid);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
c_vlenstring(Generator* generator, Symbol* sym, 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*/
|