/* Locate enums whose name is a prefix of ident and contains the suffix as an enum const and capture that enum constant. */ static List* findecmatches(char* ident) { List* matches = listnew(); int i; for(i=0;i<listlength(typdefs);i++) { int len; Symbol* ec; Symbol* en = (Symbol*)listget(typdefs,i); if(en->subclass != NC_ENUM) continue; /* First, assume that the ident is the econst name only */ ec = checkeconst(en,ident); if(ec != NULL) listpush(matches,ec); /* Second, do the prefix check */ len = strlen(en->name); if(strncmp(ident,en->name,len) == 0) { Symbol *ec; /* Find the matching ec constant, if any */ if(*(ident+len) != '.') continue; ec = checkeconst(en,ident+len+1); /* +1 for the dot */ if(ec != NULL) listpush(matches,ec); } } if(listlength(matches) == 0) { listfree(matches); matches = NULL; } return matches; }
/* We should not create an actual attribute for any of the special attributes. */ static void makespecial(int tag, Symbol* vsym, nc_type typ, Datalist* dlist) { Symbol* attr = install(specialname(tag)); attr->objectclass = NC_ATT; attr->data = dlist; if(vsym) { Symbol* grp = vsym->container; if(grp) listpush(grp->subnodes,(void*)attr); attr->container = grp; } attr->att.var = vsym; attr->typ.basetype = primsymbols[typ==NC_STRING?NC_CHAR:typ]; listpush(attdefs,(void*)attr); }
static void processenums(void) { unsigned long i,j; #if 0 /* Unused? */ List* enumids = listnew(); #endif for(i=0;i<listlength(typdefs);i++) { Symbol* sym = (Symbol*)listget(typdefs,i); ASSERT(sym->objectclass == NC_TYPE); if(sym->subclass != NC_ENUM) continue; for(j=0;j<listlength(sym->subnodes);j++) { Symbol* esym = (Symbol*)listget(sym->subnodes,j); ASSERT(esym->subclass == NC_ECONST); #if 0 /* Unused? */ listpush(enumids,(void*)esym); #endif } } /* Convert enum values to match enum type*/ for(i=0;i<listlength(typdefs);i++) { Symbol* tsym = (Symbol*)listget(typdefs,i); ASSERT(tsym->objectclass == NC_TYPE); if(tsym->subclass != NC_ENUM) continue; for(j=0;j<listlength(tsym->subnodes);j++) { Symbol* esym = (Symbol*)listget(tsym->subnodes,j); NCConstant* newec = nullconst(); ASSERT(esym->subclass == NC_ECONST); newec->nctype = esym->typ.typecode; convert1(esym->typ.econst,newec); reclaimconstant(esym->typ.econst); esym->typ.econst = newec; } } }
static void processattributes(void) { int i,j; /* process global attributes*/ for(i=0;i<listlength(gattdefs);i++) { Symbol* asym = (Symbol*)listget(gattdefs,i); /* If the attribute has a zero length, then default it */ if(asym->data == NULL || asym->data->length == 0) { asym->data = builddatalist(1); 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); /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; } /* process per variable attributes*/ for(i=0;i<listlength(attdefs);i++) { Symbol* asym = (Symbol*)listget(attdefs,i); /* If the attribute has a zero length, then default it */ if(asym->data == NULL || asym->data->length == 0) { asym->data = builddatalist(1); emptystringconst(asym->lineno,&asym->data->data[asym->data->length]); /* force type to be NC_CHAR */ asym->typ.basetype = primsymbols[NC_CHAR]; } /* 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; } /* collect per-variable attributes per variable*/ for(i=0;i<listlength(vardefs);i++) { Symbol* vsym = (Symbol*)listget(vardefs,i); List* list = listnew(); for(j=0;j<listlength(attdefs);j++) { Symbol* asym = (Symbol*)listget(attdefs,j); ASSERT(asym->att.var != NULL); if(asym->att.var != vsym) continue; listpush(list,(void*)asym); } vsym->var.attributes = list; } }
void collectpath(Symbol* grp, List* grpstack) { while(grp != NULL) { listpush(grpstack,(elem_t)grp); grp = grp->container; } }
List* prefixdup(List* prefix) { List* dupseq; int i; if(prefix == NULL) return listnew(); dupseq = listnew(); listsetalloc(dupseq,listlength(prefix)); for(i=0;i<listlength(prefix);i++) listpush(dupseq,listget(prefix,i)); return dupseq; }
static void processenums(void) { int i,j; List* enumids = listnew(); for(i=0;i<listlength(typdefs);i++) { Symbol* sym = (Symbol*)listget(typdefs,i); ASSERT(sym->objectclass == NC_TYPE); if(sym->subclass != NC_ENUM) continue; for(j=0;j<listlength(sym->subnodes);j++) { Symbol* esym = (Symbol*)listget(sym->subnodes,j); ASSERT(esym->subclass == NC_ECONST); listpush(enumids,(void*)esym); } } /* Now walk set of enum ids to look for duplicates with same prefix*/ for(i=0;i<listlength(enumids);i++) { Symbol* sym1 = (Symbol*)listget(enumids,i); for(j=i+1;j<listlength(enumids);j++) { Symbol* sym2 = (Symbol*)listget(enumids,j); if(strcmp(sym1->name,sym2->name) != 0) continue; if(!prefixeq(sym1->prefix,sym2->prefix)) continue; semerror(sym1->lineno,"Duplicate enumeration ids in same scope: %s", fullname(sym1)); } } /* Convert enum values to match enum type*/ for(i=0;i<listlength(typdefs);i++) { Symbol* tsym = (Symbol*)listget(typdefs,i); ASSERT(tsym->objectclass == NC_TYPE); if(tsym->subclass != NC_ENUM) continue; for(j=0;j<listlength(tsym->subnodes);j++) { Symbol* esym = (Symbol*)listget(tsym->subnodes,j); Constant newec; ASSERT(esym->subclass == NC_ECONST); newec.nctype = esym->typ.typecode; convert1(&esym->typ.econst,&newec); esym->typ.econst = newec; } } }
static List* ecsearchgrp(Symbol* grp, List* candidates) { List* matches = listnew(); int i,j; /* do the intersection of grp subnodes and candidates */ for(i=0;i<listlength(grp->subnodes);i++) { Symbol* sub= (Symbol*)listget(grp->subnodes,i); if(sub->subclass != NC_ENUM) continue; for(j=0;j<listlength(candidates);j++) { Symbol* ec = (Symbol*)listget(candidates,j); if(ec->container == sub) listpush(matches,ec); } } if(listlength(matches) == 0) { listfree(matches); matches = NULL; } return matches; }
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,(void*)decl); /* Now generate the reference to buffer */ bbprintf(codebuf,"{%u,(void*)vlen_%u}",count,uid); return 1; }
static void processattributes(void) { int i,j; /* process global attributes*/ for(i=0;i<listlength(gattdefs);i++) { Symbol* asym = (Symbol*)listget(gattdefs,i); if(asym->typ.basetype == NULL) inferattributetype(asym); /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; if(asym->data != NULL && asym->data->length == 0) { NCConstant* empty = NULL; /* If the attribute has a zero length, then default it; note that it must be of type NC_CHAR */ if(asym->typ.typecode != NC_CHAR) semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym)); empty = emptystringconst(asym->lineno); dlappend(asym->data,empty); } validateNIL(asym); } /* process per variable attributes*/ for(i=0;i<listlength(attdefs);i++) { Symbol* asym = (Symbol*)listget(attdefs,i); /* If no basetype is specified, then try to infer it; the exception is _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); } if(asym->att.var->var.special->_Fillvalue != NULL) reclaimdatalist(asym->att.var->var.special->_Fillvalue); asym->att.var->var.special->_Fillvalue = clonedatalist(asym->data); } else if(asym->typ.basetype == NULL) { inferattributetype(asym); } /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; if(asym->data->length == 0) { NCConstant* empty = NULL; /* If the attribute has a zero length, and is char type, then default it */ if(asym->typ.typecode != NC_CHAR) semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym)); empty = emptystringconst(asym->lineno); dlappend(asym->data,empty); } validateNIL(asym); } /* collect per-variable attributes per variable*/ for(i=0;i<listlength(vardefs);i++) { Symbol* vsym = (Symbol*)listget(vardefs,i); List* list = listnew(); for(j=0;j<listlength(attdefs);j++) { Symbol* asym = (Symbol*)listget(attdefs,j); if(asym->att.var == NULL) continue; /* ignore globals for now */ if(asym->att.var != vsym) continue; listpush(list,(void*)asym); } vsym->var.attributes = list; } }
/* 3. mark types that use vlen*/ static void processtypes(void) { unsigned long i,j; int keep,added; List* sorted = listnew(); /* hold re-ordered type set*/ /* Prime the walk by capturing the set*/ /* of types that are dependent on primitive types*/ /* e.g. uint vlen(*) or primitive types*/ for(i=0;i<listlength(typdefs);i++) { Symbol* sym = (Symbol*)listget(typdefs,i); keep=0; switch (sym->subclass) { case NC_PRIM: /*ignore pre-defined primitive types*/ sym->touched=1; break; case NC_OPAQUE: case NC_ENUM: keep=1; break; case NC_VLEN: /* keep if its basetype is primitive*/ if(sym->typ.basetype->subclass == NC_PRIM) keep=1; break; case NC_COMPOUND: /* keep if all fields are primitive*/ keep=1; /*assume all fields are primitive*/ for(j=0;j<listlength(sym->subnodes);j++) { Symbol* field = (Symbol*)listget(sym->subnodes,j); ASSERT(field->subclass == NC_FIELD); if(field->typ.basetype->subclass != NC_PRIM) {keep=0;break;} } break; default: break;/* ignore*/ } if(keep) { sym->touched = 1; listpush(sorted,(void*)sym); } } /* 2. repeated walk to collect level i types*/ do { added=0; for(i=0;i<listlength(typdefs);i++) { Symbol* sym = (Symbol*)listget(typdefs,i); if(sym->touched) continue; /* ignore already processed types*/ keep=0; /* assume not addable yet.*/ switch (sym->subclass) { case NC_PRIM: case NC_OPAQUE: case NC_ENUM: PANIC("type re-touched"); /* should never happen*/ break; case NC_VLEN: /* keep if its basetype is already processed*/ if(sym->typ.basetype->touched) keep=1; break; case NC_COMPOUND: /* keep if all fields are processed*/ keep=1; /*assume all fields are touched*/ for(j=0;j<listlength(sym->subnodes);j++) { Symbol* field = (Symbol*)listget(sym->subnodes,j); ASSERT(field->subclass == NC_FIELD); if(!field->typ.basetype->touched) {keep=1;break;} } break; default: break; } if(keep) { listpush(sorted,(void*)sym); sym->touched = 1; added++; } } } while(added > 0); /* Any untouched type => circular dependency*/ for(i=0;i<listlength(typdefs);i++) { Symbol* tsym = (Symbol*)listget(typdefs,i); if(tsym->touched) continue; semerror(tsym->lineno,"Circular type dependency for type: %s",fullname(tsym)); } listfree(typdefs); typdefs = sorted; /* fill in type typecodes*/ for(i=0;i<listlength(typdefs);i++) { Symbol* sym = (Symbol*)listget(typdefs,i); if(sym->typ.basetype != NULL && sym->typ.typecode == NC_NAT) sym->typ.typecode = sym->typ.basetype->typ.typecode; } /* Identify types containing vlens */ for(i=0;i<listlength(typdefs);i++) { Symbol* tsym = (Symbol*)listget(typdefs,i); tagvlentypes(tsym); } }
void simplifylist(char *var, statement *stmt, int start, int end) { int y = 0, channels = 0; char tmp[MAX_STRING_LENGTH], *hex; char *tmp1, *tmp2, *tmp3; char *reorder[32]; int ctr = 0; for (y=start; y<=end; y++) { oppush(0); if (get_sysvarname(stmt->metalist[y].operation)) { sprintf(tmp, "%s", get_sysvarname(stmt->metalist[y].operation)); listpush(tmp); } else if (get_fncname(stmt->metalist[y].operation)) { if ((stmt->metalist[y].operation == OP_AND) || (stmt->metalist[y].operation == OP_OR) || (stmt->metalist[y].operation == OP_XOR)) goto blah; sprintf(tmp, "%s(", get_fncname(stmt->metalist[y].operation)); if (stmt->metalist[y].intarg) { for (ctr=0; ctr<stmt->metalist[y].intarg; ctr++) { reorder[ctr] = SafeMalloc(MAX_STRING_LENGTH); reorder[ctr] = listpop(); } } else { for (ctr=0; ctr<fnctable[get_fnc(get_fncname(stmt->metalist[y]. operation))].numparms; ctr++) { reorder[ctr] = SafeMalloc(MAX_STRING_LENGTH); reorder[ctr] = listpop(); } } for (ctr=ctr-1; ctr>=0; ctr--) { strcat(tmp, reorder[ctr]); if (ctr) strcat(tmp, ","); } strcat(tmp, ")"); listpush(tmp); } else blah: switch(stmt->metalist[y].operation) { case HEXSTRING: hex = SafeMalloc(2+(stmt->metalist[y].intarg*2)); *hex = 0; sprintf(tmp, "$"); for (ctr = 0; ctr < stmt->metalist[y].intarg; ctr++) { sprintf(hex, "%X", stmt->metalist[y].stringarg[ctr]); sprintf(hex, "%c%c", hex[strlen(hex)-2], hex[strlen(hex)-1]); strcat(tmp, hex); } strcat(tmp, "$"); GC_free(hex); listpush(tmp); break; case 0xF5: if (stmt->opcode != CMD_DEFFN) listpush("<BEGINLIST>"); break; case 0xF8: if (stmt->opcode != CMD_DEFFN) { ctr = 0; do { reorder[ctr] = SafeMalloc(MAX_STRING_LENGTH); reorder[ctr] = listpop(); if (!strcmp(reorder[ctr], "<BEGINLIST>")) break; ctr++; } while(1); sprintf(tmp, "%s(", listpop()); for (ctr = ctr-1; ctr >= 0; ctr--) { strcat(tmp, reorder[ctr]); if (ctr) strcat(tmp, ","); } strcat(tmp, ")"); listpush(tmp); } break; case 0x8DC9: listpush(gprog->userfunctions[stmt->metalist[y].shortarg].name); break; case 0xF1: case 0xEC: // workaround, LET handles its own commas if (stmt->opcode != CMD_LET) { sprintf(tmp, "%s,", listpop()); listpush(tmp); for (ctr = 0; ctr < outcount; ctr++) mysprintf(var, "%s", listpop()); } break; case 0xF4F1: if (channels) mysprintf(var, ") "); break; case 0xE1: channels = 1; mysprintf(var, "(%s", listpop()); break; case OP_OPT: case OP_SEP: case OP_SRT: case OP_BNK: case OP_DOM: case OP_END: case OP_IND: case OP_IOL: case OP_ISZ: case OP_KEY: case OP_SIZ: case OP_TBL: case OP_TIM: case OP_ERR: case OP_LEN: case OP_PWD: case OP_ATR: if (channels) mysprintf(var, ", %s=%s", get_symbol(stmt->metalist[y].operation), listpop()); else { sprintf(tmp, "%s, %s=%s", listpop(), get_symbol(stmt->metalist[y].operation), listpop()); listpush(tmp); } break; case LABELREF: sprintf(tmp, "%s", get_labelname(stmt->metalist[y].shortarg)); listpush(tmp); break; case LINEREF: sprintf(tmp, "%.5d", stmt->metalist[y].shortarg); listpush(tmp); break; case MNEMONICREF: sprintf(tmp, "\'%s\'", stmt->metalist[y].stringarg); listpush(tmp); break; case 0xF7: tmp2 = listpop(); sprintf(tmp, "@(%s,%s)", listpop(), tmp2); listpush(tmp); break; case 0xF6: sprintf(tmp, "@(%s)", listpop()); listpush(tmp); break; case FLOAT: sprintf(tmp, "%s", flt2asc(stmt->metalist[y].floatarg)); listpush(tmp); break; case GETVAL_STRINGARRAY: case SETVAL_STRINGARRAY: case GETVAL_STRING: case SETVAL_STRING: ctr = stmt->metalist[y].shortarg; tmp3 = SafeMalloc(MAX_STRING_LENGTH); if (stmt->metalist[y].shortarg & 0x2000) { ctr -= 0x2000; sprintf(tmp3, "(%s)", listpop()); } else if (stmt->metalist[y].shortarg & 0x4000) { ctr -= 0x4000; tmp2 = listpop(); sprintf(tmp3, "(%s,%s)", listpop(), tmp2); } else tmp3 = 0; if (stmt->metalist[y].shortarg & 0x8000) { ctr -= 0x8000; if (stmt->metalist[y].operation == GETVAL_STRINGARRAY || stmt->metalist[y].operation == SETVAL_STRINGARRAY) { tmp1 = listpop(); tmp2 = listpop(); sprintf(tmp, "[%s,%s,%s]", listpop(), tmp2, tmp1); listpush(tmp); } else { sprintf(tmp, "[%s]", listpop()); listpush(tmp); } } else if (stmt->metalist[y].operation == GETVAL_STRINGARRAY || stmt->metalist[y].operation == SETVAL_STRINGARRAY) { tmp1 = listpop(); sprintf(tmp, "[%s,%s]", listpop(), tmp1); listpush(tmp); } else listpush(""); // noarrayref if (tmp3) sprintf(tmp, "%s%s%s", get_symname(ctr), listpop(), tmp3); else sprintf(tmp, "%s%s", get_symname(ctr), listpop()); GC_free(tmp3); if ((stmt->metalist[y].operation == SETVAL_STRING) || (stmt->metalist[y].operation == SETVAL_STRINGARRAY)) { if ((stmt->opcode == CMD_LET) || (stmt->opcode == CMD_FOR)) strcat(tmp, "="); } listpush(tmp); break; case GETVAL_NUMERIC: case SETVAL_NUMERIC: case GETVAL_NUMERICARRAY: case SETVAL_NUMERICARRAY: ctr = stmt->metalist[y].shortarg; if (stmt->metalist[y].shortarg & 0x8000) { ctr -= 0x8000; if (stmt->metalist[y].operation == GETVAL_NUMERICARRAY || stmt->metalist[y].operation == SETVAL_NUMERICARRAY) { tmp1 = listpop(); tmp2 = listpop(); sprintf(tmp, "[%s,%s,%s]", listpop(), tmp2, tmp1); listpush(tmp); } else { sprintf(tmp, "[%s]", listpop()); listpush(tmp); } } else if (stmt->metalist[y].operation == GETVAL_NUMERICARRAY || stmt->metalist[y].operation == SETVAL_NUMERICARRAY) { tmp1 = listpop(); sprintf(tmp, "[%s,%s]", listpop(), tmp1); listpush(tmp); } else listpush(""); // noarrayref sprintf(tmp, "%s%s", get_symname(ctr), listpop()); if (stmt->metalist[y].operation == SETVAL_NUMERIC || stmt->metalist[y].operation == SETVAL_NUMERICARRAY) if ((stmt->opcode == CMD_LET) || (stmt->opcode == CMD_FOR)) strcat(tmp, "="); listpush(tmp); break; case SHORTLITERAL: sprintf(tmp, "\"%s\"", stmt->metalist[y].stringarg); listpush(tmp); break; case OP_NEGATE: sprintf(tmp, "(-%s)", listpop()); listpush(tmp); break; case OP_STRCAT: tmp2 = listpop(); sprintf(tmp, "%s+%s", listpop(), tmp2); listpush(tmp); break; case OP_AND: case OP_XOR: case OP_OR: case OP_LESSTHAN: case OP_GREATTHAN: case OP_NOTEQUAL: case OP_EQUALSCMP: case OP_LTEQ: case OP_GTEQ: case OP_ADD: case OP_SUBTRACT: case OP_MULTIPLY: case OP_DIVIDE: case OP_EXPONENT: oppop(); if (oppop() >= getprec(get_symbol(stmt->metalist[y].operation))) { tmp3 = listpop(); tmp1 = SafeMalloc(strlen(tmp3)+2); sprintf(tmp1, "(%s)", tmp3); } else tmp1 = listpop(); if (oppop() >= getprec(get_symbol(stmt->metalist[y].operation))) { tmp3 = listpop(); tmp2 = SafeMalloc(strlen(tmp3)+2); sprintf(tmp2, "(%s)", tmp3); } else tmp2 = listpop(); oppush(getprec(get_symbol(stmt->metalist[y].operation))); sprintf(tmp, "%s%s%s", tmp2, get_symbol(stmt->metalist[y].operation), tmp1); listpush(tmp); break; } } }
/* * Parse per-variable chunkspec string and convert into varchunkspec structure. * ncid: location ID of open netCDF file or group in an open file * spec: string of form * var:n1,n2,...nk * * specifying chunk size (ni) to be used for ith dimension of * variable named var. Variable names may be absolute. * e.g. "/grp_a/grp_a1/var". * If no chunk sizes are specified, then the variable is not chunked at all. * * Returns NC_NOERR if no error, NC_EINVAL if spec has consecutive * unescaped commas or no chunksize specified for dimension. */ static int varchunkspec_parse(int igrp, const char *spec0) { int ret = NC_NOERR; int rank; int i; int dimids[NC_MAX_VAR_DIMS]; struct VarChunkSpec* chunkspec = NULL; char* spec = NULL; char* p, *q; /* for walking strings */ /* Copy spec so we can modify in place */ spec = strdup(spec0); if(spec == NULL) {ret = NC_ENOMEM; goto done;} chunkspec = calloc(1,sizeof(struct VarChunkSpec)); if(chunkspec == NULL) {ret = NC_ENOMEM; goto done;} chunkspec->igrpid = igrp; /* First, find the end of the variable part */ p = strchr(spec,':'); if(p == NULL) {ret = NC_EINVAL; goto done;} *p++ = '\0'; /* Lookup the variable by name */ ret = nc_inq_varid2(igrp, spec, &chunkspec->ivarid, &chunkspec->igrpid); if(ret != NC_NOERR) goto done; if(*p == '\0') {/* we have -c var: => do not chunk var */ chunkspec->omit = 1; /* add the chunkspec to our list */ listpush(varchunkspecs,chunkspec); chunkspec = NULL; goto done; } /* Iterate over dimension sizes */ while(*p) { unsigned long dimsize; q = strchr(p,','); if(q == NULL) q = p + strlen(p); /* Fake the endpoint */ else *q++ = '\0'; /* Scan as unsigned long */ if(sscanf(p,"%lu",&dimsize) != 1) {ret = NC_EINVAL; goto done;} /* Apparently not a valid dimension size */ if(chunkspec->rank >= NC_MAX_VAR_DIMS) {ret = NC_EINVAL; goto done;} /* to many chunks */ chunkspec->chunksizes[chunkspec->rank] = (size_t)dimsize; chunkspec->rank++; p = q; } /* Now do some validity checking */ /* Get some info about the var (from input) */ ret = nc_inq_var(chunkspec->igrpid,chunkspec->ivarid,NULL,NULL,&rank,dimids,NULL); if(ret != NC_NOERR) goto done; /* 1. check # chunksizes == rank of variable */ if(rank != chunkspec->rank) {ret = NC_EINVAL; goto done;} /* 2. check that chunksizes are legal for the given dimension sizes */ for(i=0;i<rank;i++) { size_t len; ret = nc_inq_dimlen(igrp,dimids[i],&len); if(ret != NC_NOERR) goto done; if(chunkspec->chunksizes[i] > len) {ret = NC_EBADCHUNK; goto done;} } /* add the chunkspec to our list */ listpush(varchunkspecs,chunkspec); chunkspec = NULL; done: if(chunkspec != NULL) free(chunkspec); if(spec != NULL) free(spec); return ret; }