1 /*********************************************************************
2 * Copyright 1993, UCAR/Unidata
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 * $Header: /upc/share/CVS/netcdf-3/ncgen/genc.c,v 1.6 2010/05/17 23:26:44 dmh Exp $
5 *********************************************************************/
6
7 #include "includes.h"
8 #include "nc_iter.h"
9 #include <ctype.h> /* for isprint() */
10
11 #ifdef ENABLE_C
12
13 #undef TRACE
14
15 /* Forward */
16 static const char* groupncid(Symbol*);
17 static const char* typencid(Symbol*);
18 static const char* varncid(Symbol*);
19 static const char* dimncid(Symbol*);
20
21 #ifdef USE_NETCDF4
22 static void definectype(Symbol*);
23 static void genc_deftype(Symbol*);
24 static void genc_definespecialattributes(Symbol* vsym);
25 static void genc_defineglobalspecials(void);
26 #endif
27
28 static void genc_defineattr(Symbol* asym);
29 static void genc_definevardata(Symbol*);
30 static void genc_write(Generator*,Symbol* sym, Bytebuffer* code,
31 int rank, size_t* start, size_t* count);
32 static void genc_writevar(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
33 static void genc_writeattr(Generator*,Symbol*,Bytebuffer*,int,size_t*,size_t*);
34
35 /*
36 * Generate C code for creating netCDF from in-memory structure.
37 */
38 void
genc_netcdf(void)39 genc_netcdf(void)
40 {
41 int idim, ivar, iatt, maxdims;
42 int ndims, nvars, natts, ngatts;
43 char* cmode_string;
44 const char *filename = rootgroup->file.filename;
45
46 #ifdef USE_NETCDF4
47 int igrp,ityp, ngrps, ntyps;
48 #endif
49
50 ndims = listlength(dimdefs);
51 nvars = listlength(vardefs);
52 natts = listlength(attdefs);
53 ngatts = listlength(gattdefs);
54 #ifdef USE_NETCDF4
55 ngrps = listlength(grpdefs);
56 ntyps = listlength(typdefs);
57 #endif /*USE_NETCDF4*/
58
59 /* wrap in main program */
60 codeline("#include <stdio.h>");
61 codeline("#include <stdlib.h>");
62 codeline("#include <netcdf.h>");
63 codeline("");
64 codeflush();
65
66 if(specialconstants) {
67 /* If the input referenced e.g. nan, inf, etc;
68 then provide definitions for them */
69 codeline("");
70 codeline("#define nanf (0.0f/0.0f)");
71 codeline("#define nan (0.0/0.0)");
72 codeline("#define inff (1.0f/0.0f)");
73 codeline("#define inf (1.0/0.0)");
74 codeline("#define infinityf inff");
75 codeline("#define infinity inf");
76 codeline("");
77 codeflush();
78 }
79 codeline("");
80 codeflush();
81
82 #ifdef USE_NETCDF4
83
84 /* Construct C type definitions*/
85 if (ntyps > 0) {
86 for(ityp = 0; ityp < ntyps; ityp++) {
87 Symbol* tsym = (Symbol*)listget(typdefs,ityp);
88 definectype(tsym);
89 }
90 codeline("");
91 }
92 codeflush();
93
94 /* Construct the chunking constants*/
95 if(!usingclassic) {
96 for(ivar=0;ivar<nvars;ivar++) {
97 Bytebuffer* tmp = bbNew();
98 Symbol* var = (Symbol*)listget(vardefs,ivar);
99 Specialdata* special = var->var.special;
100 if(special->flags & _CHUNKSIZES_FLAG) {
101 int i;
102 size_t* chunks = special->_ChunkSizes;
103 if(special->nchunks == 0 || chunks == NULL) continue;
104 bbClear(tmp);
105 for(i=0;i<special->nchunks;i++) {
106 bbprintf(tmp,"%s%ld",
107 (i == 0?"":", "),special->_ChunkSizes[i]);
108 }
109 bbprintf0(stmt,"static size_t %s_chunksizes[%d] = {",
110 cname(var),special->nchunks);
111 codedump(stmt);
112 codedump(tmp);
113 codeline("} ;");
114 }
115 if(special->flags & _FILTER_FLAG) {
116 int i;
117 unsigned int* params = special->_FilterParams;
118 if(special->nparams == 0 || params == NULL) continue;
119 bbClear(tmp);
120 for(i=0;i<special->nparams;i++) {
121 bbprintf(tmp,"%s%luU",
122 (i == 0?"":", "),params[i]);
123 }
124 bbprintf0(stmt,"static unsigned int %s_filterparams[%d] = {",
125 cname(var),special->nparams);
126 codedump(stmt);
127 codedump(tmp);
128 codeline("} ;");
129 }
130 bbFree(tmp);
131 }
132 codeline("");
133 }
134 #endif /*USE_NETCDF4*/
135
136 /* Now construct the main procedures*/
137 codeline("void");
138 codeline("check_err(const int stat, const int line, const char *file) {");
139 codelined(1,"if (stat != NC_NOERR) {");
140 codelined(2,"(void)fprintf(stderr,\"line %d of %s: %s\\n\", line, file, nc_strerror(stat));");
141 codelined(2,"fflush(stderr);");
142 codelined(2,"exit(1);");
143 codelined(1,"}");
144 codeline("}");
145 codeline("");
146 codeline("int");
147 bbprintf0(stmt,"%s() {/* create %s */\n", mainname, filename);
148 codedump(stmt);
149 /* create necessary declarations */
150 codeline("");
151 codelined(1,"int stat; /* return status */");
152 codelined(1,"int ncid; /* netCDF id */");
153 codeflush();
154
155 #ifdef USE_NETCDF4
156 /* Define variables to hold group ids*/
157 if(!usingclassic) {
158 codeline("");
159 codelined(1,"/* group ids */");
160 }
161 if(!usingclassic && ngrps > 0) {
162 for(igrp = 0; igrp < ngrps; igrp++) {
163 Symbol* gsym = (Symbol*)listget(grpdefs,igrp);
164 bbprintf0(stmt,"%sint %s;\n",indented(1),groupncid(gsym));
165 codedump(stmt);
166 }
167 }
168
169 /* define variables to hold type ids*/
170 if(!usingclassic && ntyps > 0) {
171 codeline("");
172 codelined(1,"/* type ids */");
173 for(ityp = 0; ityp < ntyps; ityp++) {
174 Symbol* tsym = (Symbol*)listget(typdefs,ityp);
175 bbprintf0(stmt,"%sint %s;\n",indented(1), typencid(tsym));
176 codedump(stmt);
177 }
178 }
179 codeflush();
180 #endif
181
182 if (ndims > 0) {
183 codeline("");
184 codelined(1,"/* dimension ids */");
185 for(idim = 0; idim < ndims; idim++) {
186 Symbol* dsym = (Symbol*)listget(dimdefs,idim);
187 bbprintf0(stmt,"%sint %s;\n", indented(1), dimncid(dsym));
188 codedump(stmt);
189 }
190
191 codeline("");
192 codelined(1,"/* dimension lengths */");
193 for(idim = 0; idim < ndims; idim++) {
194 Symbol* dsym = (Symbol*)listget(dimdefs,idim);
195 if(dsym->dim.isunlimited) {
196 bbprintf0(stmt,"%ssize_t %s_len = NC_UNLIMITED;\n",
197 indented(1),cname(dsym));
198 } else {
199 bbprintf0(stmt,"%ssize_t %s_len = %lu;\n",
200 indented(1),
201 cname(dsym),
202 (unsigned long) dsym->dim.declsize);
203 }
204 codedump(stmt);
205 }
206 }
207 codeflush();
208
209 maxdims = 0; /* most dimensions of any variable */
210 for(ivar = 0; ivar < nvars; ivar++) {
211 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
212 if(vsym->typ.dimset.ndims > maxdims)
213 maxdims = vsym->typ.dimset.ndims;
214 }
215
216 if (nvars > 0) {
217 codeline("");
218 codelined(1,"/* variable ids */");
219 for(ivar = 0; ivar < nvars; ivar++) {
220 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
221 bbprintf0(stmt," int %s;\n", varncid(vsym));
222 codedump(stmt);
223 }
224
225 codeline("");
226 codelined(1,"/* rank (number of dimensions) for each variable */");
227 for(ivar = 0; ivar < nvars; ivar++) {
228 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
229 bbprintf0(stmt,"# define RANK_%s %d\n", cname(vsym),
230 vsym->typ.dimset.ndims);
231 codedump(stmt);
232 }
233 if (maxdims > 0) { /* we have dimensioned variables */
234 codeline("");
235 codelined(1,"/* variable shapes */");
236 for(ivar = 0; ivar < nvars; ivar++) {
237 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
238 if (vsym->typ.dimset.ndims > 0) {
239 bbprintf0(stmt," int %s_dims[RANK_%s];\n",
240 cname(vsym), cname(vsym));
241 codedump(stmt);
242 }
243 }
244 }
245 }
246 codeflush();
247
248 /* Set log level */
249 if(ncloglevel >= 0) {
250 codeline("");
251 bbprintf0(stmt," nc_set_log_level(%d); /* set log level */",ncloglevel);
252 codedump(stmt);
253 codeline("");
254 }
255
256 /* create netCDF file, uses NC_CLOBBER mode */
257 codeline("");
258 codelined(1,"/* enter define mode */");
259
260 if (!cmode_modifier) {
261 cmode_string = "NC_CLOBBER";
262 } else if (cmode_modifier & NC_64BIT_OFFSET) {
263 cmode_string = "NC_CLOBBER|NC_64BIT_OFFSET";
264 #ifdef USE_NETCDF4
265 } else if (cmode_modifier & NC_CLASSIC_MODEL) {
266 cmode_string = "NC_CLOBBER|NC_NETCDF4|NC_CLASSIC_MODEL";
267 } else if (cmode_modifier & NC_NETCDF4) {
268 cmode_string = "NC_CLOBBER|NC_NETCDF4";
269 #endif
270 } else {
271 derror("unknown cmode modifier");
272 cmode_string = "NC_CLOBBER";
273 }
274 bbprintf0(stmt," stat = nc_create(\"%s\", %s, &ncid);\n",
275 filename,cmode_string);
276 codedump(stmt);
277 codelined(1,"check_err(stat,__LINE__,__FILE__);");
278 codeflush();
279
280 #ifdef USE_NETCDF4
281 genc_defineglobalspecials();
282 #endif /*USE_NETCDF4*/
283
284 #ifdef USE_NETCDF4
285 /* Define the group structure */
286 /* ncid created above is also root group*/
287 if(!usingclassic) {
288 bbprintf0(stmt," %s = ncid;\n",groupncid(rootgroup));
289 codedump(stmt);
290 /* walking grpdefs list will do a preorder walk of all defined groups*/
291 for(igrp=0;igrp<listlength(grpdefs);igrp++) {
292 Symbol* gsym = (Symbol*)listget(grpdefs,igrp);
293 if(gsym == rootgroup) continue; /* ignore root*/
294 if(gsym->container == NULL)
295 PANIC("null container");
296 bbprintf0(stmt,
297 " stat = nc_def_grp(%s, \"%s\", &%s);\n",
298 groupncid(gsym->container),
299 gsym->name, groupncid(gsym));
300 codedump(stmt);
301 codelined(1,"check_err(stat,__LINE__,__FILE__);");
302 }
303 codeflush();
304 }
305 #endif
306
307 #ifdef USE_NETCDF4
308 /* Construct code to define types*/
309 if(ntyps > 0) {
310 codeline("");
311 for(ityp = 0; ityp < ntyps; ityp++) {
312 Symbol* tsym = (Symbol*)listget(typdefs,ityp);
313 if(tsym->subclass == NC_PRIM
314 || tsym->subclass == NC_ARRAY) continue; /* no need to do these*/
315 genc_deftype(tsym);
316 codeline("");
317 }
318 }
319 codeflush();
320 #endif
321
322 /* define dimensions from info in dims array */
323 if (ndims > 0) {
324 codeline("");
325 codelined(1,"/* define dimensions */");
326 for(idim = 0; idim < ndims; idim++) {
327 Symbol* dsym = (Symbol*)listget(dimdefs,idim);
328 {
329 bbprintf0(stmt,
330 " stat = nc_def_dim(%s, \"%s\", %s_len, &%s);\n",
331 groupncid(dsym->container),
332 escapifyname(dsym->name),
333 cname(dsym),
334 dimncid(dsym));
335 }
336 codedump(stmt);
337 codelined(1,"check_err(stat,__LINE__,__FILE__);");
338 }
339 }
340 codeflush();
341
342 /* define variables from info in vars array */
343 if (nvars > 0) {
344 codeline("");
345 codelined(1,"/* define variables */");
346 for(ivar = 0; ivar < nvars; ivar++) {
347 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
348 Symbol* basetype = vsym->typ.basetype;
349 Dimset* dimset = &vsym->typ.dimset;
350 codeline("");
351 if(dimset->ndims > 0) {
352 for(idim = 0; idim < dimset->ndims; idim++) {
353 Symbol* dsym = dimset->dimsyms[idim];
354 bbprintf0(stmt,
355 " %s_dims[%d] = %s;\n",
356 cname(vsym),
357 idim,
358 dimncid(dsym));
359 codedump(stmt);
360 }
361 }
362 bbprintf0(stmt,
363 " stat = nc_def_var(%s, \"%s\", %s, RANK_%s, %s, &%s);\n",
364 groupncid(vsym->container),
365 escapifyname(vsym->name),
366 typencid(basetype),
367 cname(vsym),
368 (dimset->ndims == 0?"0":poolcat(cname(vsym),"_dims")),
369 varncid(vsym));
370 codedump(stmt);
371 codelined(1,"check_err(stat,__LINE__,__FILE__);");
372 #ifdef USE_NETCDF4
373 genc_definespecialattributes(vsym);
374 #endif /*USE_NETCDF4*/
375 }
376 }
377 codeflush();
378
379 /* Define the global attributes*/
380 if(ngatts > 0) {
381 codeline("");
382 codelined(1,"/* assign global attributes */");
383 for(iatt = 0; iatt < ngatts; iatt++) {
384 Symbol* gasym = (Symbol*)listget(gattdefs,iatt);
385 genc_defineattr(gasym);
386 }
387 codeline("");
388 }
389 codeflush();
390
391 /* Define the variable specific attributes*/
392 if(natts > 0) {
393 codeline("");
394 codelined(1,"/* assign per-variable attributes */");
395 for(iatt = 0; iatt < natts; iatt++) {
396 Symbol* asym = (Symbol*)listget(attdefs,iatt);
397 genc_defineattr(asym);
398 }
399 codeline("");
400 }
401 codeflush();
402
403 if (nofill_flag) {
404 codelined(1,"/* don't initialize variables with fill values */");
405 bbindent(stmt,1);
406 bbprintf0(stmt,"stat = nc_set_fill(%s, NC_NOFILL, 0);",groupncid(rootgroup));
407 codelined(1,"check_err(stat,__LINE__,__FILE__);");
408 }
409
410 codeline("");
411 codelined(1,"/* leave define mode */");
412 bbprintf0(stmt," stat = nc_enddef (%s);\n",groupncid(rootgroup));
413 codedump(stmt);
414 codelined(1,"check_err(stat,__LINE__,__FILE__);");
415 codeflush();
416
417 if(!header_only) {
418 /* Load values into those variables with defined data */
419 if(nvars > 0) {
420 codeline("");
421 codelined(1,"/* assign variable data */");
422 for(ivar = 0; ivar < nvars; ivar++) {
423 Symbol* vsym = (Symbol*)listget(vardefs,ivar);
424 if(vsym->data != NULL) genc_definevardata(vsym);
425 }
426 codeline("");
427 }
428 codeflush();
429 }
430 }
431
432 #ifdef USE_NETCDF4
433
434 static void
genc_defineglobalspecials(void)435 genc_defineglobalspecials(void)
436 {
437 const char* format = NULL;
438 if(usingclassic) return;
439 if(!/*Main.*/format_attribute) return;
440 /* Watch out, this is a global Attribute */
441 format = kind_string(globalspecials._Format);
442 bbprintf0(stmt,"%sstat = nc_put_att_text(ncid, NC_GLOBAL, \"_Format\", 1, \"%s\");\n",
443 indented(1),
444 format);
445 codedump(stmt);
446 codelined(1,"check_err(stat,__LINE__,__FILE__);");
447 }
448
449 static void
genc_definespecialattributes(Symbol * vsym)450 genc_definespecialattributes(Symbol* vsym)
451 {
452 Specialdata* special = vsym->var.special;
453 if(usingclassic) return;
454 if(special->flags & _STORAGE_FLAG) {
455 int storage = special->_Storage;
456 size_t* chunks = special->_ChunkSizes;
457 bbprintf0(stmt,
458 " stat = nc_def_var_chunking(%s, %s, %s, ",
459 groupncid(vsym->container),
460 varncid(vsym),
461 (storage == NC_CONTIGUOUS?"NC_CONTIGUOUS":"NC_CHUNKED"));
462 codedump(stmt);
463 if(special->nchunks == 0 || chunks == NULL)
464 codepartial("NULL");
465 else {
466 bbprintf0(stmt,"%s_chunksizes",cname(vsym));
467 codedump(stmt);
468 }
469 codeline(");");
470 codelined(1,"check_err(stat,__LINE__,__FILE__);");
471 }
472 if(special->flags & _FLETCHER32_FLAG) {
473 bbprintf0(stmt,
474 " stat = nc_def_var_fletcher32(%s, %s, %d);\n",
475 groupncid(vsym->container),
476 varncid(vsym),
477 special->_Fletcher32);
478 codedump(stmt);
479 codelined(1,"check_err(stat,__LINE__,__FILE__);");
480 }
481 if(special->flags & (_DEFLATE_FLAG | _SHUFFLE_FLAG)) {
482 bbprintf0(stmt,
483 " stat = nc_def_var_deflate(%s, %s, %s, %d, %d);\n",
484 groupncid(vsym->container),
485 varncid(vsym),
486 (special->_Shuffle == 1?"NC_SHUFFLE":"NC_NOSHUFFLE"),
487 (special->_DeflateLevel >= 0?1:0),
488 (special->_DeflateLevel >= 0?special->_DeflateLevel:0));
489 codedump(stmt);
490 codelined(1,"check_err(stat,__LINE__,__FILE__);");
491 }
492 if(special->flags & _ENDIAN_FLAG) {
493 bbprintf0(stmt,
494 " stat = nc_def_var_endian(%s, %s, %s);\n",
495 groupncid(vsym->container),
496 varncid(vsym),
497 (special->_Endianness == NC_ENDIAN_LITTLE?"NC_ENDIAN_LITTLE"
498 :"NC_ENDIAN_BIG")
499 );
500 codedump(stmt);
501 codelined(1,"check_err(stat,__LINE__,__FILE__);");
502 }
503 if(special->flags & _NOFILL_FLAG) {
504 bbprintf0(stmt,
505 " stat = nc_def_var_fill(%s, %s, %s, NULL);\n",
506 groupncid(vsym->container),
507 varncid(vsym),
508 (special->_Fill?"NC_FILL":"NC_NOFILL")
509 );
510 codedump(stmt);
511 codelined(1,"check_err(stat,__LINE__,__FILE__);");
512 }
513 if(special->flags & _FILTER_FLAG) {
514 /* Special check for alternate way to specify _Deflate */
515 if(special->_FilterID == ZIP_ID) {
516 unsigned int level;
517 if(special->nparams == 0 || special->_FilterParams == NULL)
518 level = 9; /* default */
519 else
520 level = special->_FilterParams[0];
521 if(level > 9)
522 derror("Illegal deflate level");
523 else {
524 bbprintf0(stmt,
525 " stat = nc_def_var_deflate(%s, %s, %s, %d, %d);\n",
526 groupncid(vsym->container),
527 varncid(vsym),
528 (special->_Shuffle == 1?"NC_SHUFFLE":"NC_NOSHUFFLE"),
529 1,
530 level);
531 codedump(stmt);
532 }
533 } else {
534 bbprintf0(stmt,
535 " stat = nc_def_var_filter(%s, %s, %u, %lu, ",
536 groupncid(vsym->container),
537 varncid(vsym),
538 special->_FilterID,
539 special->nparams
540 );
541 codedump(stmt);
542 if(special->nparams == 0 || special->_FilterParams == NULL)
543 codepartial("NULL");
544 else {
545 bbprintf0(stmt,"%s_filterparams",cname(vsym));
546 codedump(stmt);
547 }
548 codeline(");");
549 }
550 codelined(1,"check_err(stat,__LINE__,__FILE__);");
551 }
552
553
554 }
555 #endif /*USE_NETCDF4*/
556
557 void
genc_close(void)558 genc_close(void)
559 {
560 bbprintf0(stmt,"%sstat = nc_close(%s);\n",indented(1),groupncid(rootgroup));
561 codedump(stmt);
562 codelined(1,"check_err(stat,__LINE__,__FILE__);");
563 #ifndef vms
564 codelined(1,"return 0;");
565 #else
566 codelined(1,"return 1;");
567 #endif
568 codeline("}");
569 codeflush();
570 }
571
572 /*
573 * Output a C statement
574 */
575
576
577
578 /* return C name for netCDF type, given type code */
579 const char *
nctype(nc_type type)580 nctype(nc_type type)
581 {
582 switch (type) {
583 case NC_CHAR: return "NC_CHAR";
584 case NC_BYTE: return "NC_BYTE";
585 case NC_SHORT: return "NC_SHORT";
586 case NC_INT: return "NC_INT";
587 case NC_FLOAT: return "NC_FLOAT";
588 case NC_DOUBLE: return "NC_DOUBLE";
589 case NC_UBYTE: return "NC_UBYTE";
590 case NC_USHORT: return "NC_USHORT";
591 case NC_UINT: return "NC_UINT";
592 case NC_INT64: return "NC_INT64";
593 case NC_UINT64: return "NC_UINT64";
594 case NC_STRING: return "NC_STRING";
595 default: PANIC("nctype: bad type code");
596 }
597 return NULL;
598 }
599
600
601
602 /*
603 * Return C type name for netCDF type, given type code.
604 */
605 const char*
ncctype(nc_type type)606 ncctype(nc_type type)
607 {
608 switch (type) {
609 case NC_CHAR:
610 return "char";
611 case NC_BYTE:
612 return "signed char";
613 case NC_SHORT:
614 return "short";
615 case NC_INT:
616 return "int";
617 case NC_FLOAT:
618 return "float";
619 case NC_DOUBLE:
620 return "double";
621 case NC_UBYTE:
622 return "unsigned char";
623 case NC_USHORT:
624 return "unsigned short";
625 case NC_UINT:
626 return "unsigned int";
627 case NC_INT64:
628 return "signed long long";
629 case NC_UINT64:
630 return "unsigned long long";
631 case NC_STRING:
632 return "char*";
633 default:
634 PANIC1("ncctype: bad type code:%d",type);
635 }
636 return 0;
637 }
638
639 /*
640 * Return C type name for netCDF type suffix, given type code.
641 */
642 const char*
ncstype(nc_type nctype)643 ncstype(nc_type nctype)
644 {
645 switch (nctype) {
646 case NC_CHAR:
647 return "text";
648 case NC_BYTE:
649 return "schar";
650 case NC_SHORT:
651 return "short";
652 case NC_INT:
653 return "int";
654 case NC_FLOAT:
655 return "float";
656 case NC_DOUBLE:
657 return "double";
658 case NC_UBYTE:
659 return "ubyte";
660 case NC_USHORT:
661 return "ushort";
662 case NC_UINT:
663 return "uint";
664 case NC_INT64:
665 return "longlong";
666 case NC_UINT64:
667 return "ulonglong";
668 case NC_STRING:
669 return "string";
670 default:
671 derror("ncstype: bad type code: %d",nctype);
672 return 0;
673 }
674 }
675
676 /* Return the group name for the specified group*/
677 static const char*
groupncid(Symbol * sym)678 groupncid(Symbol* sym)
679 {
680 #ifdef USE_NETCDF4
681 if(usingclassic) {
682 return "ncid";
683 } else {
684 char* grptmp;
685 const char* tmp1;
686 if(sym == NULL) return groupncid(rootgroup);
687 ASSERT(sym->objectclass == NC_GRP);
688 tmp1 = cname(sym);
689 grptmp = poolalloc(strlen(tmp1)+strlen("_grp")+1);
690 strcpy(grptmp,tmp1);
691 strcat(grptmp,"_grp");
692 return grptmp;
693 }
694 #else
695 return "ncid";
696 #endif
697 }
698
699 /* Compute the C name for a given type's id*/
700 /* Watch out: the result is a static*/
701 static const char*
typencid(Symbol * tsym)702 typencid(Symbol* tsym)
703 {
704 char* typtmp;
705 const char* tmp1;
706 if(tsym->subclass == NC_PRIM)
707 return nctype(tsym->typ.typecode);
708 tmp1 = ctypename(tsym);
709 typtmp = poolalloc(strlen(tmp1)+strlen("_typ")+1);
710 strcpy(typtmp,tmp1);
711 strcat(typtmp,"_typ");
712 return typtmp;
713 }
714
715 /* Compute the C name for a given var's id*/
716 /* Watch out: the result is a static*/
717 static const char*
varncid(Symbol * vsym)718 varncid(Symbol* vsym)
719 {
720 const char* tmp1;
721 char* vartmp;
722 tmp1 = cname(vsym);
723 vartmp = poolalloc(strlen(tmp1)+strlen("_id")+1);
724 strcpy(vartmp,tmp1);
725 strcat(vartmp,"_id");
726 return vartmp;
727 }
728
729 /* Compute the C name for a given dim's id*/
730 /* Watch out: the result is pooled*/
731 static const char*
dimncid(Symbol * dsym)732 dimncid(Symbol* dsym)
733 {
734 const char* tmp1;
735 char* dimtmp;
736 tmp1 = cname(dsym);
737 dimtmp = poolalloc(strlen(tmp1)+strlen("_dim")+1);
738 strcpy(dimtmp,tmp1);
739 strcat(dimtmp,"_dim");
740 return dimtmp;
741 }
742
743 /* Compute the C name for a given type*/
744 const char*
ctypename(Symbol * tsym)745 ctypename(Symbol* tsym)
746 {
747 const char* name;
748 ASSERT(tsym->objectclass == NC_TYPE);
749 if(tsym->subclass == NC_PRIM)
750 name = ncctype(tsym->typ.typecode);
751 else
752 name = cname(tsym);
753 return name;
754 }
755
756 #ifdef USE_NETCDF4
757 static void
definectype(Symbol * tsym)758 definectype(Symbol* tsym)
759 {
760 int i,j;
761
762 ASSERT(tsym->objectclass == NC_TYPE);
763 switch (tsym->subclass) {
764 case NC_PRIM: break; /* these are already taken care of*/
765 case NC_OPAQUE:
766 bbprintf0(stmt,"typedef unsigned char %s[%lu];\n",
767 cname(tsym), tsym->typ.size);
768 codedump(stmt);
769 break;
770 case NC_ENUM:
771 for(i=0;i<listlength(tsym->subnodes);i++) {
772 Symbol* econst = (Symbol*)listget(tsym->subnodes,i);
773 Bytebuffer* econststring = bbNew();
774 ASSERT(econst->subclass == NC_ECONST);
775 c_generator->constant(c_generator,tsym,econst->typ.econst,econststring);
776 bbNull(econststring);
777 /* Enum constants must be converted to a fully qualified name */
778 bbprintf0(stmt,"#define %s ((%s)%s)\n",
779 cname(econst),
780 ctypename(econst->typ.basetype),
781 bbContents(econststring));
782 bbFree(econststring);
783 codedump(stmt);
784 }
785 bbprintf0(stmt,"typedef %s %s;\n",
786 ctypename(tsym->typ.basetype), cname(tsym));
787 codedump(stmt);
788 break;
789 case NC_VLEN:
790 bbprintf0(stmt,"typedef nc_vlen_t %s;\n",
791 ctypename(tsym));
792 codedump(stmt);
793 break;
794 case NC_COMPOUND:
795 bbprintf0(stmt,"typedef struct %s {\n",cname(tsym));
796 codedump(stmt);
797 for(i=0;i<listlength(tsym->subnodes);i++) {
798 Symbol* efield = (Symbol*)listget(tsym->subnodes,i);
799 ASSERT(efield->subclass == NC_FIELD);
800 bbprintf0(stmt,"%s%s %s",
801 indented(1),ctypename(efield->typ.basetype),cname(efield));
802 codedump(stmt);
803 /* compute any dimension specification*/
804 if(efield->typ.dimset.ndims > 0) {
805 Bytebuffer* dimbuf = bbNew();
806 for(j=0;j<efield->typ.dimset.ndims;j++) {
807 Symbol* dim;
808 char tmp[64];
809 bbCat(dimbuf,"[");
810 dim = efield->typ.dimset.dimsyms[j];
811 ASSERT(dim->dim.isconstant);
812 snprintf(tmp,sizeof(tmp),"%u",
813 (unsigned int)dim->dim.declsize);
814 bbCat(dimbuf,tmp);
815 bbCat(dimbuf,"]");
816 }
817 codedump(dimbuf);
818 bbFree(dimbuf);
819 }
820 codeline(";");
821 }
822 bbprintf0(stmt,"} %s;\n", ctypename(tsym));
823 codedump(stmt);
824 break;
825
826 case NC_ARRAY:
827 /* ignore: this will be handled by def_var*/
828 break;
829
830 default: panic("definectype: unexpected type subclass: %d",tsym->subclass);
831 }
832 }
833
834 /*
835 Generate the C code for defining a given type
836 */
837 static void
genc_deftype(Symbol * tsym)838 genc_deftype(Symbol* tsym)
839 {
840 int i;
841
842 ASSERT(tsym->objectclass == NC_TYPE);
843 switch (tsym->subclass) {
844 case NC_PRIM: break; /* these are already taken care of*/
845 case NC_OPAQUE:
846 bbprintf0(stmt,"%sstat = nc_def_opaque(%s, %lu, \"%s\", &%s);\n",
847 indented(1),
848 groupncid(tsym->container),
849 tsym->typ.size,
850 tsym->name,
851 typencid(tsym));
852 codedump(stmt);
853 codelined(1,"check_err(stat,__LINE__,__FILE__);");
854 break;
855 case NC_ENUM:
856 codelined(1,"{");
857 bbprintf0(stmt,"%s%s econst;\n",
858 indented(1),
859 ncctype(tsym->typ.basetype->typ.typecode));
860 codedump(stmt);
861 bbprintf0(stmt,"%sstat = nc_def_enum(%s, %s, \"%s\", &%s);\n",
862 indented(1),
863 groupncid(tsym->container),
864 nctype(tsym->typ.basetype->typ.typecode),
865 tsym->name,
866 typencid(tsym));
867 codedump(stmt);
868 codelined(1,"check_err(stat,__LINE__,__FILE__);");
869 for(i=0;i<listlength(tsym->subnodes);i++) {
870 Symbol* econst = (Symbol*)listget(tsym->subnodes,i);
871 Bytebuffer* econststring = bbNew();
872 ASSERT(econst->subclass == NC_ECONST);
873 c_generator->constant(c_generator,tsym,econst->typ.econst,econststring);
874 bbNull(econststring);
875 bbprintf0(stmt,"%seconst = %s;\n",
876 indented(1),bbContents(econststring));
877 bbFree(econststring);
878 codedump(stmt);
879 bbprintf0(stmt,"%sstat = nc_insert_enum(%s, %s, \"%s\", &econst);\n",
880 indented(1),
881 groupncid(tsym->container),
882 typencid(tsym),
883 escapifyname(econst->name));
884 codedump(stmt);
885 }
886 codelined(1,"}");
887 break;
888 case NC_VLEN:
889 bbprintf0(stmt,"%sstat = nc_def_vlen(%s, \"%s\", %s, &%s);",
890 indented(1),
891 groupncid(tsym->container),
892 escapifyname(tsym->name),
893 typencid(tsym->typ.basetype),
894 typencid(tsym));
895 codedump(stmt);
896 codelined(1,"check_err(stat,__LINE__,__FILE__);");
897 break;
898 case NC_COMPOUND:
899 bbprintf0(stmt,"%sstat = nc_def_compound(%s, sizeof(%s), \"%s\", &%s);",
900 indented(1),
901 groupncid(tsym->container),
902 ctypename(tsym),
903 escapifyname(tsym->name),
904 typencid(tsym));
905 codedump(stmt);
906 codelined(1,"check_err(stat,__LINE__,__FILE__);");
907 /* Generate the field dimension constants*/
908 codelined(1,"{");
909 for(i=0;i<listlength(tsym->subnodes);i++) {
910 int j;
911 Symbol* efield = (Symbol*)listget(tsym->subnodes,i);
912 ASSERT(efield->subclass == NC_FIELD);
913 if(efield->typ.dimset.ndims == 0) continue;
914 bbprintf0(stmt,"%sstatic int %s_dims[%d] = {\n",
915 indented(1),
916 cname(efield),efield->typ.dimset.ndims);
917 for(j=0;j<efield->typ.dimset.ndims;j++) {
918 char tmp[256];
919 Symbol* e = efield->typ.dimset.dimsyms[j];
920 ASSERT(e->dim.isconstant);
921 snprintf(tmp,sizeof(tmp),"%u",(unsigned int)e->dim.declsize);
922 bbCat(stmt,(j==0?"":", "));
923 bbCat(stmt,tmp);
924 }
925 bbCat(stmt,"};");
926 codedump(stmt);
927 }
928 for(i=0;i<listlength(tsym->subnodes);i++) {
929 Symbol* efield = (Symbol*)listget(tsym->subnodes,i);
930 char tmp[1024];
931 ASSERT(efield->subclass == NC_FIELD);
932 #ifdef TESTALIGNMENT
933 snprintf(tmp,sizeof(tmp),"%lu",efield->typ.offset);
934 #else
935 snprintf(tmp,sizeof(tmp),"NC_COMPOUND_OFFSET(%s,%s)",
936 ctypename(tsym), cname(efield));
937 #endif
938 if(efield->typ.dimset.ndims > 0){
939 bbprintf0(stmt,"%sstat = nc_insert_array_compound(%s, %s, \"%s\", %s, %s, %d, %s_dims);",
940 indented(1),
941 groupncid(tsym->container),
942 typencid(tsym),
943 escapifyname(efield->name),
944 tmp,
945 typencid(efield->typ.basetype),
946 efield->typ.dimset.ndims,
947 cname(efield));
948 } else {
949 bbprintf0(stmt,"%sstat = nc_insert_compound(%s, %s, \"%s\", %s, %s);",
950 indented(1),
951 groupncid(tsym->container),
952 typencid(tsym),
953 escapifyname(efield->name),
954 tmp,
955 typencid(efield->typ.basetype));
956 }
957 codedump(stmt);
958 codelined(1,"check_err(stat,__LINE__,__FILE__);");
959 }
960 codelined(1,"}");
961 break;
962
963 case NC_ARRAY:
964 /* ignore: this will be handled by def_var*/
965 break;
966
967 default: panic("genc_deftype: unexpected type subclass: %d",tsym->subclass);
968 }
969 }
970
971 #endif /*USE_NETCDF4*/
972
973 static void
genc_defineattr(Symbol * asym)974 genc_defineattr(Symbol* asym)
975 {
976 /* we need to capture vlen strings for dumping */
977 Bytebuffer* save = bbNew(); /* capture so we can dump
978 vlens first */
979 List* oldstate = NULL;
980 generator_getstate(c_generator,(void*)&oldstate);
981 listfree(oldstate);
982 generator_reset(c_generator,(void*)listnew());
983 generate_attrdata(asym,c_generator,(Writer)genc_write,save);
984 bbFree(save);
985 }
986
987 static void
genc_definevardata(Symbol * vsym)988 genc_definevardata(Symbol* vsym)
989 {
990 Bytebuffer* save; /* capture so we can dump vlens first */
991 List* oldstate = NULL;
992 if(vsym->data == NULL) return;
993 save = bbNew();
994 generator_getstate(c_generator,(void*)&oldstate);
995 listfree(oldstate);
996 generator_reset(c_generator,(void*)listnew());
997 generate_vardata(vsym,c_generator,(Writer)genc_write,save);
998 bbFree(save);
999 }
1000
1001 static void
genc_write(Generator * generator,Symbol * sym,Bytebuffer * code,int rank,size_t * start,size_t * count)1002 genc_write(Generator* generator, Symbol* sym, Bytebuffer* code,
1003 int rank, size_t* start, size_t* count)
1004 {
1005 if(sym->objectclass == NC_ATT)
1006 genc_writeattr(generator,sym,code,rank,start,count);
1007 else if(sym->objectclass == NC_VAR)
1008 genc_writevar(generator,sym,code,rank,start,count);
1009 else
1010 PANIC("illegal symbol for genc_write");
1011 }
1012
1013 static void
genc_writevar(Generator * generator,Symbol * vsym,Bytebuffer * code,int rank,size_t * start,size_t * count)1014 genc_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
1015 int rank, size_t* start, size_t* count)
1016 {
1017 Symbol* basetype = vsym->typ.basetype;
1018 nc_type typecode = basetype->typ.typecode;
1019 List* vlendecls;
1020
1021 /* define a block to avoid name clashes*/
1022 codeline("");
1023 codelined(1,"{");
1024
1025 /* Dump any vlen decls first */
1026 generator_getstate(generator,(void**)&vlendecls);
1027 if(vlendecls != NULL && listlength(vlendecls) > 0) {
1028 int i;
1029 for(i=0;i<listlength(vlendecls);i++) {
1030 Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
1031 codelined(1,bbContents(decl));
1032 bbFree(decl);
1033 }
1034 listfree(vlendecls);
1035 generator_reset(generator,NULL);
1036 }
1037
1038 if(rank == 0) {
1039 codelined(1,"size_t count = 0;");
1040 /* We make the data be an array so we do not need to
1041 ampersand it later => we need an outer pair of braces
1042 */
1043 commify(code); /* insert commas at proper places */
1044 bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
1045 indented(1),
1046 ctypename(basetype),
1047 cname(vsym),
1048 bbContents(code));
1049 codedump(stmt);
1050 bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &count, %s_data);\n",
1051 indented(1),
1052 groupncid(vsym->container),
1053 varncid(vsym),
1054 cname(vsym));
1055 codedump(stmt);
1056 codelined(1,"check_err(stat,__LINE__,__FILE__);");
1057 codeflush();
1058 } else { /* rank > 0 */
1059 int i;
1060 size_t length = 0;
1061 if(typecode == NC_CHAR) {
1062 length = bbLength(code);
1063 /* generate data constant */
1064 bbprintf(stmt,"%schar* %s_data = ",
1065 indented(1),
1066 cname(vsym),
1067 (unsigned long)length);
1068 codedump(stmt);
1069 cquotestring(code,'"');
1070 codedump(code);
1071 codeline(" ;");
1072 } else {
1073 /* Compute total size */
1074 length = 1;
1075 for(i=0;i<rank;i++) length *= count[i];
1076 /* generate data constant */
1077 commify(code); /* insert commas at proper places */
1078 bbprintf(stmt,"%s%s %s_data[%lu] = ",
1079 indented(1),
1080 ctypename(basetype),
1081 cname(vsym),
1082 (unsigned long)length);
1083 codedump(stmt);
1084 /* C requires an outer set of braces on datalist constants */
1085 codepartial("{");
1086 codedump(code);
1087 codeline("} ;");
1088 }
1089
1090 /* generate constants for startset, countset*/
1091 bbprintf0(stmt,"%ssize_t %s_startset[%u] = {",
1092 indented(1),
1093 cname(vsym),
1094 rank);
1095 for(i=0;i<rank;i++) {
1096 bbprintf(stmt,"%s%lu",(i>0?", ":""),start[i]);
1097 }
1098 codedump(stmt);
1099 codeline("} ;");
1100
1101 bbprintf0(stmt,"%ssize_t %s_countset[%u] = {",
1102 indented(1),
1103 cname(vsym),
1104 rank);
1105 for(i=0;i<rank;i++) {
1106 bbprintf(stmt,"%s%lu",(i>0?", ":""),count[i]);
1107 }
1108 codedump(stmt);
1109 codeline("};");
1110
1111 bbprintf0(stmt,"%sstat = nc_put_vara(%s, %s, %s_startset, %s_countset, %s_data);\n",
1112 indented(1),
1113 groupncid(vsym->container), varncid(vsym),
1114 cname(vsym),
1115 cname(vsym),
1116 cname(vsym));
1117 codedump(stmt);
1118 codelined(1,"check_err(stat,__LINE__,__FILE__);");
1119
1120 }
1121 /* end defined block*/
1122 codelined(1,"}\n");
1123 codeflush();
1124 }
1125
1126 static void
genc_writeattr(Generator * generator,Symbol * asym,Bytebuffer * code,int rank,size_t * start,size_t * count)1127 genc_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
1128 int rank, size_t* start, size_t* count)
1129 {
1130 Symbol* basetype = asym->typ.basetype;
1131 int typecode = basetype->typ.typecode;
1132 size_t len = asym->data->length; /* default assumption */
1133
1134 /* define a block to avoid name clashes*/
1135 codeline("");
1136 codelined(1,"{");
1137
1138 /* Handle NC_CHAR specially */
1139 if(typecode == NC_CHAR) {
1140 len = bbLength(code); /* presumably before quoting */
1141 /* Revise length if length == 0 */
1142 if(len == 0) len++;
1143 cquotestring(code,'"');
1144 } else {
1145 /* All other cases */
1146 /* Dump any vlen decls first */
1147 List* vlendecls;
1148 generator_getstate(generator,(void**)&vlendecls);
1149 if(vlendecls != NULL && listlength(vlendecls) > 0) {
1150 int i;
1151 for(i=0;i<listlength(vlendecls);i++) {
1152 Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
1153 codelined(1,bbContents(decl));
1154 bbFree(decl);
1155 }
1156 listfree(vlendecls);
1157 generator_reset(generator,NULL);
1158 }
1159 commify(code);
1160 bbprintf0(stmt,"%sstatic const %s %s_att[%ld] = ",
1161 indented(1),
1162 ctypename(basetype),
1163 cname(asym),
1164 asym->data->length
1165 );
1166 codedump(stmt);
1167 codepartial("{");
1168 codedump(code);
1169 codepartial("}");
1170 codeline(" ;");
1171 bbClear(code);
1172 }
1173
1174 /* Use the specialized put_att_XX routines if possible*/
1175 switch (basetype->typ.typecode) {
1176 case NC_BYTE:
1177 case NC_SHORT:
1178 case NC_INT:
1179 case NC_FLOAT:
1180 case NC_DOUBLE:
1181 bbprintf0(stmt,"%sstat = nc_put_att_%s(%s, %s, \"%s\", %s, %lu, %s_att);\n",
1182 indented(1),
1183 ncstype(basetype->typ.typecode),
1184 groupncid(asym->container),
1185 (asym->att.var == NULL?"NC_GLOBAL"
1186 :varncid(asym->att.var)),
1187 escapifyname(asym->name),
1188 typencid(basetype),
1189 len,
1190 cname(asym));
1191 codedump(stmt);
1192 break;
1193
1194 case NC_CHAR:
1195 /* Include the string constant in-line */
1196 bbprintf0(stmt,"%sstat = nc_put_att_%s(%s, %s, \"%s\", %lu, %s);\n",
1197 indented(1),
1198 ncstype(basetype->typ.typecode),
1199 groupncid(asym->container),
1200 (asym->att.var == NULL?"NC_GLOBAL"
1201 :varncid(asym->att.var)),
1202 escapifyname(asym->name),
1203 len,
1204 bbContents(code));
1205 codedump(stmt);
1206 break;
1207
1208 /* !usingclassic only (except NC_STRING) */
1209 case NC_UBYTE:
1210 case NC_USHORT:
1211 case NC_UINT:
1212 case NC_INT64:
1213 case NC_UINT64:
1214 if(usingclassic && k_flag <= 2) {
1215 verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
1216 return;
1217 }
1218 bbprintf0(stmt,"%sstat = nc_put_att_%s(%s, %s, \"%s\", %s, %lu, %s_att);",
1219 indented(1),
1220 ncstype(basetype->typ.typecode),
1221 groupncid(asym->container),
1222 (asym->att.var == NULL?"NC_GLOBAL"
1223 :varncid(asym->att.var)),
1224 escapifyname(asym->name),
1225 typencid(basetype),
1226 len,
1227 cname(asym));
1228 codedump(stmt);
1229 break;
1230
1231 #ifdef USE_NETCDF4
1232 case NC_STRING:
1233 if(usingclassic) {
1234 verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
1235 return;
1236 }
1237 bbprintf0(stmt,"%sstat = nc_put_att_%s(%s, %s, \"%s\", %lu, %s_att);",
1238 indented(1),
1239 ncstype(basetype->typ.typecode),
1240 groupncid(asym->container),
1241 (asym->att.var == NULL?"NC_GLOBAL"
1242 :varncid(asym->att.var)),
1243 escapifyname(asym->name),
1244 len,
1245 cname(asym));
1246 codedump(stmt);
1247 break;
1248 #endif
1249
1250 default: /* User defined type */
1251 #ifndef USE_NETCDF4
1252 verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
1253 #else /* !USE_NETCDF4 */
1254 if(usingclassic && !isclassicprim(basetype->typ.typecode)) {
1255 verror("Non-classic type: %s",nctypename(basetype->typ.typecode));
1256 }
1257 bbprintf0(stmt,"%sstat = nc_put_att(%s, %s, \"%s\", %s, %lu, %s_att);\n",
1258 indented(1),
1259 groupncid(asym->container),
1260 (asym->att.var == NULL?"NC_GLOBAL"
1261 :varncid(asym->att.var)),
1262 escapifyname(asym->name),
1263 typencid(basetype),
1264 len,
1265 cname(asym));
1266 codedump(stmt);
1267 #endif
1268 break;
1269 }
1270
1271 codelined(1,"check_err(stat,__LINE__,__FILE__);");
1272 codelined(1,"}");
1273 }
1274
1275
1276 /* Compute the C name for a given symbol;
1277 modified to use the fqn
1278 */
1279 const char*
cname(Symbol * sym)1280 cname(Symbol* sym)
1281 {
1282 char* name;
1283
1284 assert (sym->fqn != NULL && sym->name != NULL);
1285 /* Convert the fqn as its C name. */
1286 if(sym->grp.is_root)
1287 name = codify(sym->name);
1288 else
1289 name = codify(sym->fqn);
1290 return name;
1291 }
1292
1293 #endif /*ENABLE_C*/
1294