1 /*********************************************************************
2  *   Copyright 2018, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Id: ncgen.y,v 1.42 2010/05/18 21:32:46 dmh Exp $
5  *********************************************************************/
6 
7 /* yacc source for "ncgen", a netCDL parser and netCDF generator */
8 
9 %error-verbose
10 
11 %{
12 /*
13 static char SccsId[] = "$Id: ncgen.y,v 1.42 2010/05/18 21:32:46 dmh Exp $";
14 */
15 #include        "includes.h"
16 #include        "netcdf_aux.h"
17 #include        "ncgeny.h"
18 #include        "ncgen.h"
19 #ifdef USE_NETCDF4
20 #include        "netcdf_filter.h"
21 #endif
22 
23 /* Following are in ncdump (for now)*/
24 /* Need some (unused) definitions to get it to compile */
25 #define ncatt_t void*
26 #define ncvar_t void
27 #include "nctime.h"
28 
29 /* parser controls */
30 #define YY_NO_INPUT 1
31 
32 /* True if string a equals string b*/
33 #ifndef NCSTREQ
34 #define NCSTREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
35 #endif
36 #define VLENSIZE  (sizeof(nc_vlen_t))
37 #define MAXFLOATDIM 4294967295.0
38 
39 /* mnemonics */
40 typedef enum Attrkind {ATTRVAR, ATTRGLOBAL, DONTKNOW} Attrkind;
41 
42 #define ISCONST 1
43 #define ISLIST 0
44 
45 typedef nc_vlen_t vlen_t;
46 
47 /* We retain the old representation of the symbol list
48    as a linked list.
49 */
50 List* symlist;
51 
52 /* Track rootgroup separately*/
53 Symbol* rootgroup;
54 
55 /* Track the group sequence */
56 static List* groupstack;
57 
58 /* Provide a separate sequence for accumulating values
59    during the parse.
60 */
61 static List* stack;
62 
63 /* track homogeneity of types for data lists*/
64 static nc_type consttype;
65 
66 /* Misc. */
67 static int stackbase;
68 static int stacklen;
69 static int count;
70 static int opaqueid; /* counter for opaque constants*/
71 static int arrayuid; /* counter for pseudo-array types*/
72 
73 char* primtypenames[PRIMNO] = {
74 "nat",
75 "byte", "char", "short",
76 "int", "float", "double",
77 "ubyte", "ushort", "uint",
78 "int64", "uint64",
79 "string"
80 };
81 
82 static int GLOBAL_SPECIAL = _NCPROPS_FLAG
83                             | _ISNETCDF4_FLAG
84                             | _SUPERBLOCK_FLAG
85                             | _FORMAT_FLAG ;
86 
87 /*Defined in ncgen.l*/
88 extern int lineno;              /* line number for error messages */
89 extern Bytebuffer* lextext;           /* name or string with escapes removed */
90 
91 extern double double_val;       /* last double value read */
92 extern float float_val;         /* last float value read */
93 extern long long int64_val;         /* last int64 value read */
94 extern int int32_val;             /* last int32 value read */
95 extern short int16_val;         /* last short value read */
96 extern unsigned long long uint64_val;         /* last int64 value read */
97 extern unsigned int uint32_val;             /* last int32 value read */
98 extern unsigned short uint16_val;         /* last short value read */
99 extern char char_val;           /* last char value read */
100 extern signed char byte_val;    /* last byte value read */
101 extern unsigned char ubyte_val;    /* last byte value read */
102 
103 /* Track definitions of dims, types, attributes, and vars*/
104 List* grpdefs;
105 List* dimdefs;
106 List* attdefs; /* variable-specific attributes*/
107 List* gattdefs; /* global attributes only*/
108 List* xattdefs; /* unknown attributes*/
109 List* typdefs;
110 List* vardefs;
111 List* condefs; /* non-dimension constants used in type defs*/
112 List* tmp;
113 
114 /* Forward */
115 static NCConstant* makeconstdata(nc_type);
116 static NCConstant* evaluate(Symbol* fcn, Datalist* arglist);
117 static NCConstant* makeenumconstref(Symbol*);
118 static void addtogroup(Symbol*);
119 static Symbol* currentgroup(void);
120 static Symbol* createrootgroup(const char*);
121 static Symbol* creategroup(Symbol*);
122 static int dupobjectcheck(nc_class,Symbol*);
123 static void setpathcurrent(Symbol* sym);
124 static Symbol* makeattribute(Symbol*,Symbol*,Symbol*,Datalist*,Attrkind);
125 static Symbol* makeprimitivetype(nc_type i);
126 static Symbol* makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst);
127 static int containsfills(Datalist* list);
128 static void vercheck(int ncid);
129 static long long extractint(NCConstant* con);
130 #ifdef USE_NETCDF4
131 static int parsefilterflag(const char* sdata0, Specialdata* special);
132 #ifdef GENDEBUG1
133 static void printfilters(size_t nfilters, NC_ParsedFilterSpec** filters);
134 #endif
135 #endif
136 
137 int yylex(void);
138 
139 #ifndef NO_STDARG
140 static void yyerror(const char *fmt, ...);
141 #else
142 static void yyerror(fmt,va_alist) const char* fmt; va_dcl;
143 #endif
144 
145 /* Extern */
146 extern int lex_init(void);
147 
148 %}
149 
150 /* DECLARATIONS */
151 
152 %union {
153 Symbol* sym;
154 unsigned long  size; /* allow for zero size to indicate e.g. UNLIMITED*/
155 long           mark; /* track indices into the sequence*/
156 int            nctype; /* for tracking attribute list type*/
157 Datalist*      datalist;
158 NCConstant*    constant;
159 }
160 
161 %token <sym>
162         NC_UNLIMITED_K /* keyword for unbounded record dimension */
163         CHAR_K      /* keyword for char datatype */
164         BYTE_K      /* keyword for byte datatype */
165         SHORT_K     /* keyword for short datatype */
166         INT_K       /* keyword for int datatype */
167         FLOAT_K     /* keyword for float datatype */
168         DOUBLE_K    /* keyword for double datatype */
169         UBYTE_K     /* keyword for unsigned byte datatype */
170         USHORT_K    /* keyword for unsigned short datatype */
171         UINT_K      /* keyword for unsigned int datatype */
172         INT64_K     /* keyword for long long datatype */
173         UINT64_K    /* keyword for unsigned long long datatype */
174         STRING_K    /* keyword for string datatype */
175         IDENT       /* name for a dimension, variable, or attribute */
176         TERMSTRING  /* terminal string */
177         CHAR_CONST  /* char constant (not ever generated by ncgen.l) */
178         BYTE_CONST  /* byte constant */
179         SHORT_CONST /* short constant */
180         INT_CONST   /* int constant */
181         INT64_CONST   /* long long constant */
182         UBYTE_CONST  /* unsigned byte constant */
183         USHORT_CONST /* unsigned short constant */
184         UINT_CONST   /* unsigned int  constant */
185         UINT64_CONST   /* unsigned long long  constant */
186         FLOAT_CONST /* float constant */
187         DOUBLE_CONST/* double constant */
188         DIMENSIONS  /* keyword starting dimensions section, if any */
189         VARIABLES   /* keyword starting variables section, if any */
190         NETCDF      /* keyword declaring netcdf name */
191         DATA        /* keyword starting data section, if any */
192         TYPES
193 	COMPOUND
194         ENUM
195         OPAQUE_ /* 'OPAQUE' apparently conflicts with HDF4 code */
196         OPAQUESTRING    /* 0x<even number of hexdigits> */
197         GROUP
198 	PATH            /* / or (/IDENT)+(.IDENT)? */
199 	FILLMARKER	/* "_" as opposed to the attribute */
200 	NIL             /* NIL */
201         _FILLVALUE
202         _FORMAT
203         _STORAGE
204         _CHUNKSIZES
205         _DEFLATELEVEL
206         _SHUFFLE
207         _ENDIANNESS
208         _NOFILL
209         _FLETCHER32
210 	_NCPROPS
211 	_ISNETCDF4
212 	_SUPERBLOCK
213 	_FILTER
214 	DATASETID
215 
216 %type <sym> ident typename primtype dimd varspec
217 	    attrdecl enumid path dimref fielddim fieldspec
218 %type <sym> typeref
219 %type <sym> varref
220 %type <sym> type_var_ref
221 %type <mark> enumidlist fieldlist fields varlist dimspec dimlist field
222 	     fielddimspec fielddimlist
223 %type <constant> dataitem constdata constint conststring constbool
224 %type <constant> simpleconstant function econstref
225 %type <datalist> datalist intlist datalist1 datalist0 arglist
226 
227 
228 %start  ncdesc /* start symbol for grammar */
229 
230 %%
231 
232 /* RULES */
233 
234 ncdesc: NETCDF
235 	datasetid
236         rootgroup
237         {if (error_count > 0) YYABORT;}
238         ;
239 
240 datasetid: DATASETID {createrootgroup(datasetname);};
241 
242 rootgroup: '{'
243            groupbody
244            subgrouplist
245            '}';
246 
247 /* 2/3/08 - Allow group body with only attributes. (H/T John Storrs). */
248 groupbody:
249 		attrdecllist
250                 typesection     /* Type definitions */
251                 dimsection      /* dimension declarations */
252                 vasection       /* variable and attribute declarations */
253                 datasection     /* data for variables within the group */
254                 ;
255 
256 subgrouplist: /*empty*/ | subgrouplist namedgroup;
257 
258 namedgroup: GROUP ident '{'
259             {
260 		Symbol* id = $2;
261                 markcdf4("Group specification");
262 		if(creategroup(id) == NULL)
263                     yyerror("duplicate group declaration within parent group for %s",
264                                 id->name);
265             }
266             groupbody
267             subgrouplist
268             {listpop(groupstack);}
269             '}'
270 	    attrdecllist
271 	    ;
272 
273 typesection:    /* empty */
274                 | TYPES {}
275 		| TYPES typedecls
276 			{markcdf4("Type specification");}
277                 ;
278 
279 typedecls: type_or_attr_decl | typedecls type_or_attr_decl ;
280 
281 typename: ident
282 	    { /* Use when defining a type */
283               $1->objectclass = NC_TYPE;
284               if(dupobjectcheck(NC_TYPE,$1))
285                     yyerror("duplicate type declaration for %s",
286                             $1->name);
287               listpush(typdefs,(void*)$1);
288 	    }
289 	  ;
290 
291 type_or_attr_decl: typedecl {} | attrdecl ';' {} ;
292 
293 typedecl:
294 	  enumdecl optsemicolon
295 	| compounddecl optsemicolon
296 	| vlendecl optsemicolon
297 	| opaquedecl optsemicolon
298 	;
299 
300 optsemicolon: /*empty*/ | ';' ;
301 
302 
303 enumdecl: primtype ENUM typename
304           '{' enumidlist '}'
305               {
306 		int i;
307                 addtogroup($3); /* sets prefix*/
308                 $3->objectclass=NC_TYPE;
309                 $3->subclass=NC_ENUM;
310                 $3->typ.basetype=$1;
311                 $3->typ.size = $1->typ.size;
312                 $3->typ.alignment = $1->typ.alignment;
313                 stackbase=$5;
314                 stacklen=listlength(stack);
315                 $3->subnodes = listnew();
316                 /* Variety of field fixups*/
317 		/* 1. add in the enum values*/
318 		/* 2. make this type be their container*/
319 		/* 3. make constant names visible in the group*/
320 		/* 4. set field basetype to be same as enum basetype*/
321                 for(i=stackbase;i<stacklen;i++) {
322                    Symbol* eid = (Symbol*)listget(stack,i);
323 		   assert(eid->subclass == NC_ECONST);
324 		   addtogroup(eid);
325                    listpush($3->subnodes,(void*)eid);
326                    eid->container = $3;
327 		   eid->typ.basetype = $3->typ.basetype;
328                 }
329                 listsetlength(stack,stackbase);/* remove stack nodes*/
330               }
331           ;
332 
333 enumidlist:   enumid
334 		{$$=listlength(stack); listpush(stack,(void*)$1);}
335 	    | enumidlist ',' enumid
336 		{
337 		    int i;
338 		    $$=$1;
339 		    /* check for duplicates*/
340 		    stackbase=$1;
341 		    stacklen=listlength(stack);
342 		    for(i=stackbase;i<stacklen;i++) {
343 		      Symbol* elem = (Symbol*)listget(stack,i);
344 		      if(strcmp($3->name,elem->name)==0)
345   	                yyerror("duplicate enum declaration for %s",
346         	                 elem->name);
347 		    }
348 		    listpush(stack,(void*)$3);
349 		}
350 	    ;
351 
352 enumid: ident '=' constint
353         {
354             $1->objectclass=NC_TYPE;
355             $1->subclass=NC_ECONST;
356             $1->typ.econst=$3;
357 	    $$=$1;
358         }
359         ;
360 
361 opaquedecl: OPAQUE_ '(' INT_CONST ')' typename
362                 {
363 		    vercheck(NC_OPAQUE);
364                     addtogroup($5); /*sets prefix*/
365                     $5->objectclass=NC_TYPE;
366                     $5->subclass=NC_OPAQUE;
367                     $5->typ.typecode=NC_OPAQUE;
368                     $5->typ.size=int32_val;
369                     $5->typ.alignment=ncaux_class_alignment(NC_OPAQUE);
370                 }
371             ;
372 
373 vlendecl: typeref '(' '*' ')' typename
374                 {
375                     Symbol* basetype = $1;
376 		    vercheck(NC_VLEN);
377                     addtogroup($5); /*sets prefix*/
378                     $5->objectclass=NC_TYPE;
379                     $5->subclass=NC_VLEN;
380                     $5->typ.basetype=basetype;
381                     $5->typ.typecode=NC_VLEN;
382                     $5->typ.size=VLENSIZE;
383                     $5->typ.alignment=ncaux_class_alignment(NC_VLEN);
384                 }
385           ;
386 
387 compounddecl: COMPOUND typename '{' fields '}'
388           {
389 	    int i,j;
390 	    vercheck(NC_COMPOUND);
391             addtogroup($2);
392 	    /* check for duplicate field names*/
393 	    stackbase=$4;
394 	    stacklen=listlength(stack);
395 	    for(i=stackbase;i<stacklen;i++) {
396 	      Symbol* elem1 = (Symbol*)listget(stack,i);
397 	      for(j=i+1;j<stacklen;j++) {
398 	          Symbol* elem2 = (Symbol*)listget(stack,j);
399 	          if(strcmp(elem1->name,elem2->name)==0) {
400 	            yyerror("duplicate field declaration for %s",elem1->name);
401 		  }
402 	      }
403 	    }
404 	    $2->objectclass=NC_TYPE;
405             $2->subclass=NC_COMPOUND;
406             $2->typ.basetype=NULL;
407             $2->typ.typecode=NC_COMPOUND;
408 	    $2->subnodes = listnew();
409 	    /* Add in the fields*/
410 	    for(i=stackbase;i<stacklen;i++) {
411 	        Symbol* fsym = (Symbol*)listget(stack,i);
412 		fsym->container = $2;
413  	        listpush($2->subnodes,(void*)fsym);
414 	    }
415 	    listsetlength(stack,stackbase);/* remove stack nodes*/
416           }
417             ;
418 
419 
420 fields:   field ';' {$$=$1;}
421 	   | fields field ';' {$$=$1;}
422 	   ;
423 
424 field: typeref fieldlist
425         {
426 	    int i;
427 	    $$=$2;
428 	    stackbase=$2;
429 	    stacklen=listlength(stack);
430 	    /* process each field in the fieldlist*/
431             for(i=stackbase;i<stacklen;i++) {
432                 Symbol* f = (Symbol*)listget(stack,i);
433 		f->typ.basetype = $1;
434             }
435         }
436         ;
437 
438 primtype:         CHAR_K  { $$ = primsymbols[NC_CHAR]; }
439                 | BYTE_K  { $$ = primsymbols[NC_BYTE]; }
440                 | SHORT_K { $$ = primsymbols[NC_SHORT]; }
441                 | INT_K   { $$ = primsymbols[NC_INT]; }
442                 | FLOAT_K { $$ = primsymbols[NC_FLOAT]; }
443                 | DOUBLE_K{ $$ = primsymbols[NC_DOUBLE]; }
444                 | UBYTE_K  { vercheck(NC_UBYTE); $$ = primsymbols[NC_UBYTE]; }
445                 | USHORT_K { vercheck(NC_USHORT); $$ = primsymbols[NC_USHORT]; }
446                 | UINT_K   { vercheck(NC_UINT); $$ = primsymbols[NC_UINT]; }
447                 | INT64_K   { vercheck(NC_INT64); $$ = primsymbols[NC_INT64]; }
448                 | UINT64_K   { vercheck(NC_UINT64); $$ = primsymbols[NC_UINT64]; }
449                 | STRING_K   { vercheck(NC_STRING); $$ = primsymbols[NC_STRING]; }
450                 ;
451 
452 dimsection:     /* empty */
453                 | DIMENSIONS {}
454 		| DIMENSIONS dimdecls {}
455                 ;
456 
457 dimdecls:       dim_or_attr_decl ';'
458                 | dimdecls dim_or_attr_decl ';'
459                 ;
460 
461 dim_or_attr_decl: dimdeclist {} | attrdecl {} ;
462 
463 dimdeclist:     dimdecl
464                 | dimdeclist ',' dimdecl
465                 ;
466 
467 dimdecl:
468 	  dimd '=' constint
469               {
470 		$1->dim.declsize = (size_t)extractint($3);
471 #ifdef GENDEBUG1
472 fprintf(stderr,"dimension: %s = %llu\n",$1->name,(unsigned long long)$1->dim.declsize);
473 #endif
474 		reclaimconstant($3);
475 	      }
476         | dimd '=' NC_UNLIMITED_K
477                    {
478 		        $1->dim.declsize = NC_UNLIMITED;
479 		        $1->dim.isunlimited = 1;
480 #ifdef GENDEBUG1
481 fprintf(stderr,"dimension: %s = UNLIMITED\n",$1->name);
482 #endif
483 		   }
484                 ;
485 
486 dimd:           ident
487                    {
488                      $1->objectclass=NC_DIM;
489                      if(dupobjectcheck(NC_DIM,$1))
490                         yyerror( "Duplicate dimension declaration for %s",
491                                 $1->name);
492 		     addtogroup($1);
493 		     $$=$1;
494 		     listpush(dimdefs,(void*)$1);
495                    }
496                 ;
497 
498 vasection:      /* empty */
499                 | VARIABLES {}
500                 | VARIABLES vadecls {}
501                 ;
502 
503 vadecls:        vadecl_or_attr ';'
504                 | vadecls vadecl_or_attr ';'
505                 ;
506 
507 vadecl_or_attr: vardecl {} | attrdecl {} ;
508 
509 vardecl:        typeref varlist
510 		{
511 		    int i;
512 		    stackbase=$2;
513 		    stacklen=listlength(stack);
514 		    /* process each variable in the varlist*/
515 	            for(i=stackbase;i<stacklen;i++) {
516 	                Symbol* sym = (Symbol*)listget(stack,i);
517 			sym->objectclass = NC_VAR;
518 		        if(dupobjectcheck(NC_VAR,sym)) {
519                             yyerror("Duplicate variable declaration for %s",
520                                     sym->name);
521 			} else {
522 		  	    sym->typ.basetype = $1;
523 	                    addtogroup(sym);
524 		            listpush(vardefs,(void*)sym);
525 			    sym->var.special = ecalloc(sizeof(Specialdata));
526 			    if(sym->var.special == NULL)
527 			        derror("out of memory");
528 			}
529 		    }
530 		    listsetlength(stack,stackbase);/* remove stack nodes*/
531 		}
532                 ;
533 
534 varlist:      varspec
535 	        {$$=listlength(stack);
536                  listpush(stack,(void*)$1);
537 		}
538             | varlist ',' varspec
539 	        {$$=$1; listpush(stack,(void*)$3);}
540             ;
541 
542 varspec:        ident dimspec
543                     {
544 		    int i;
545 		    Dimset dimset;
546 		    Symbol* var = $1; /* for debugging */
547 		    stacklen=listlength(stack);
548 		    stackbase=$2;
549 		    count = stacklen - stackbase;
550 		    if(count >= NC_MAX_VAR_DIMS) {
551 			yyerror("%s has too many dimensions",$1->name);
552 			count = NC_MAX_VAR_DIMS - 1;
553 			stacklen = stackbase + count;
554 		    }
555   	            dimset.ndims = count;
556 		    /* extract the actual dimensions*/
557 		    if(dimset.ndims > 0) {
558 		        for(i=0;i<count;i++) {
559 			    Symbol* dsym = (Symbol*)listget(stack,stackbase+i);
560 			    dimset.dimsyms[i] = dsym;
561 			}
562 			var->typ.dimset = dimset;
563 		    }
564 		    var->typ.basetype = NULL; /* not yet known*/
565                     var->objectclass=NC_VAR;
566 		    listsetlength(stack,stackbase);/* remove stack nodes*/
567 		    $$ = var;
568 		    }
569                 ;
570 
571 dimspec:        /* empty */ {$$=listlength(stack);}
572                 | '(' dimlist ')' {$$=$2;}
573                 ;
574 
575 dimlist:        dimref {$$=listlength(stack); listpush(stack,(void*)$1);}
576                 | dimlist ',' dimref
577 		    {$$=$1; listpush(stack,(void*)$3);}
578                 ;
579 
580 dimref: path
581             {Symbol* dimsym = $1;
582 		dimsym->objectclass = NC_DIM;
583 		/* Find the actual dimension*/
584 		dimsym = locate(dimsym);
585 		if(dimsym == NULL) {
586 		    derror("Undefined or forward referenced dimension: %s",$1->name);
587 		    YYABORT;
588 		}
589 		$$=dimsym;
590 	    }
591 	;
592 
593 fieldlist:
594 	  fieldspec
595 	    {$$=listlength(stack);
596              listpush(stack,(void*)$1);
597 	    }
598 	| fieldlist ',' fieldspec
599 	    {$$=$1; listpush(stack,(void*)$3);}
600         ;
601 
602 fieldspec:
603 	ident fielddimspec
604 	    {
605 		int i;
606 		Dimset dimset;
607 		stackbase=$2;
608 		stacklen=listlength(stack);
609 		count = stacklen - stackbase;
610 		if(count >= NC_MAX_VAR_DIMS) {
611 		    yyerror("%s has too many dimensions",$1->name);
612 		    count = NC_MAX_VAR_DIMS - 1;
613 		    stacklen = stackbase + count;
614 		}
615   	        dimset.ndims = count;
616 		if(count > 0) {
617 		    /* extract the actual dimensions*/
618 		    for(i=0;i<count;i++) {
619 		        Symbol* dsym = (Symbol*)listget(stack,stackbase+i);
620 		        dimset.dimsyms[i] = dsym;
621 		    }
622 		    $1->typ.dimset = dimset;
623 		}
624 		$1->typ.basetype = NULL; /* not yet known*/
625                 $1->objectclass=NC_TYPE;
626                 $1->subclass=NC_FIELD;
627 		listsetlength(stack,stackbase);/* remove stack nodes*/
628 		$$ = $1;
629 	    }
630 	;
631 
632 fielddimspec:        /* empty */ {$$=listlength(stack);}
633                 | '(' fielddimlist ')' {$$=$2;}
634                 ;
635 
636 fielddimlist:
637 	  fielddim {$$=listlength(stack); listpush(stack,(void*)$1);}
638 	| fielddimlist ',' fielddim
639 	    {$$=$1; listpush(stack,(void*)$3);}
640         ;
641 
642 fielddim:
643 	  UINT_CONST
644 	    {  /* Anonymous integer dimension.
645 	         Can only occur in type definitions*/
646 	     char anon[32];
647 	     sprintf(anon,"const%u",uint32_val);
648 	     $$ = install(anon);
649 	     $$->objectclass = NC_DIM;
650 	     $$->dim.isconstant = 1;
651 	     $$->dim.declsize = uint32_val;
652 	    }
653 	| INT_CONST
654 	    {  /* Anonymous integer dimension.
655 	         Can only occur in type definitions*/
656 	     char anon[32];
657 	     if(int32_val <= 0) {
658 		derror("field dimension must be positive");
659 		YYABORT;
660 	     }
661 	     sprintf(anon,"const%d",int32_val);
662 	     $$ = install(anon);
663 	     $$->objectclass = NC_DIM;
664 	     $$->dim.isconstant = 1;
665 	     $$->dim.declsize = int32_val;
666 	    }
667 	;
668 
669 
670 /* Use this when referencing defined objects */
671 
672 varref:
673 	type_var_ref
674 	    {Symbol* vsym = $1;
675 		if(vsym->objectclass != NC_VAR) {
676 		    derror("Undefined or forward referenced variable: %s",vsym->name);
677 		    YYABORT;
678 		}
679 		$$=vsym;
680 	    }
681 	  ;
682 
683 typeref:
684 	type_var_ref
685 	    {Symbol* tsym = $1;
686 		if(tsym->objectclass != NC_TYPE) {
687 		    derror("Undefined or forward referenced type: %s",tsym->name);
688 		    YYABORT;
689 		}
690 		$$=tsym;
691 	    }
692 	;
693 
694 type_var_ref:
695 	path
696 	    {Symbol* tvsym = $1; Symbol* sym;
697 		/* disambiguate*/
698 		tvsym->objectclass = NC_VAR;
699 		sym = locate(tvsym);
700 		if(sym == NULL) {
701 		    tvsym->objectclass = NC_TYPE;
702 		    sym = locate(tvsym);
703 		    if(tvsym == NULL) {
704 		        derror("Undefined or forward referenced name: %s",$1->name);
705 		        YYABORT;
706 		    } else tvsym = sym;
707 		} else tvsym = sym;
708 		if(tvsym == NULL) {
709 		    derror("Undefined name (line %d): %s",$1->lineno,$1->name);
710 		    YYABORT;
711 		}
712 		$$=tvsym;
713 	    }
714 	| primtype {$$=$1;}
715 	;
716 
717 /* Use this for all attribute decls */
718 /* Global vs var-specific will be separated in makeattribute */
719 
720 /* Watch out; this is left recursive */
721 attrdecllist: /*empty*/ {} | attrdecl ';' attrdecllist {} ;
722 
723 attrdecl:
724 	  ':' _NCPROPS '=' conststring
725 	    {$$ = makespecial(_NCPROPS_FLAG,NULL,NULL,(void*)$4,ISCONST);}
726 	| ':' _ISNETCDF4 '=' constbool
727 	    {$$ = makespecial(_ISNETCDF4_FLAG,NULL,NULL,(void*)$4,ISCONST);}
728 	| ':' _SUPERBLOCK '=' constint
729 	    {$$ = makespecial(_SUPERBLOCK_FLAG,NULL,NULL,(void*)$4,ISCONST);}
730 	| ':' ident '=' datalist
731 	    { $$=makeattribute($2,NULL,NULL,$4,ATTRGLOBAL);}
732 	| typeref type_var_ref ':' ident '=' datalist
733 	    {Symbol* tsym = $1; Symbol* vsym = $2; Symbol* asym = $4;
734 		if(vsym->objectclass == NC_VAR) {
735 		    $$=makeattribute(asym,vsym,tsym,$6,ATTRVAR);
736 		} else {
737 		    derror("Doubly typed attribute: %s",asym->name);
738 		    YYABORT;
739 		}
740 	    }
741 	| type_var_ref ':' ident '=' datalist
742 	    {Symbol* sym = $1; Symbol* asym = $3;
743 		if(sym->objectclass == NC_VAR) {
744 		    $$=makeattribute(asym,sym,NULL,$5,ATTRVAR);
745 		} else if(sym->objectclass == NC_TYPE) {
746 		    $$=makeattribute(asym,NULL,sym,$5,ATTRGLOBAL);
747 		} else {
748 		    derror("Attribute prefix not a variable or type: %s",asym->name);
749 		    YYABORT;
750 		}
751 	    }
752 	| type_var_ref ':' _FILLVALUE '=' datalist
753 	    {$$ = makespecial(_FILLVALUE_FLAG,$1,NULL,(void*)$5,ISLIST);}
754 	| typeref type_var_ref ':' _FILLVALUE '=' datalist
755 	    {$$ = makespecial(_FILLVALUE_FLAG,$2,$1,(void*)$6,ISLIST);}
756 	| type_var_ref ':' _STORAGE '=' conststring
757 	    {$$ = makespecial(_STORAGE_FLAG,$1,NULL,(void*)$5,ISCONST);}
758 	| type_var_ref ':' _CHUNKSIZES '=' intlist
759 	    {$$ = makespecial(_CHUNKSIZES_FLAG,$1,NULL,(void*)$5,ISLIST);}
760 	| type_var_ref ':' _FLETCHER32 '=' constbool
761 	    {$$ = makespecial(_FLETCHER32_FLAG,$1,NULL,(void*)$5,ISCONST);}
762 	| type_var_ref ':' _DEFLATELEVEL '=' constint
763 	    {$$ = makespecial(_DEFLATE_FLAG,$1,NULL,(void*)$5,ISCONST);}
764 	| type_var_ref ':' _SHUFFLE '=' constbool
765 	    {$$ = makespecial(_SHUFFLE_FLAG,$1,NULL,(void*)$5,ISCONST);}
766 	| type_var_ref ':' _ENDIANNESS '=' conststring
767 	    {$$ = makespecial(_ENDIAN_FLAG,$1,NULL,(void*)$5,ISCONST);}
768 	| type_var_ref ':' _FILTER '=' conststring
769 	    {$$ = makespecial(_FILTER_FLAG,$1,NULL,(void*)$5,ISCONST);}
770 	| type_var_ref ':' _NOFILL '=' constbool
771 	    {$$ = makespecial(_NOFILL_FLAG,$1,NULL,(void*)$5,ISCONST);}
772 	| ':' _FORMAT '=' conststring
773 	    {$$ = makespecial(_FORMAT_FLAG,NULL,NULL,(void*)$4,ISCONST);}
774 	;
775 
776 path:
777 	  ident
778 	    {
779 	        $$=$1;
780                 $1->ref.is_ref=1;
781                 $1->is_prefixed=0;
782                 setpathcurrent($1);
783 	    }
784 	| PATH
785 	    {
786 	        $$=$1;
787                 $1->ref.is_ref=1;
788                 $1->is_prefixed=1;
789 	        /* path is set in ncgen.l*/
790 	    }
791 	;
792 
793 datasection:    /* empty */
794                 | DATA {}
795                 | DATA datadecls {}
796                 ;
797 
798 datadecls:      datadecl ';'
799                 | datadecls datadecl ';'
800                 ;
801 
802 datadecl:       varref '=' datalist
803                    {$1->data = $3;}
804                 ;
805 datalist:
806 	  datalist0 {$$ = $1;}
807 	| datalist1 {$$ = $1;}
808 	;
809 
810 datalist0:
811 	/*empty*/ {$$ = builddatalist(0);}
812 	;
813 
814 datalist1: /* Must have at least 1 element */
815 	  dataitem {$$ = const2list($1);}
816 	| datalist ',' dataitem
817 	    {dlappend($1,($3)); $$=$1; }
818 	;
819 
820 dataitem:
821 	  constdata {$$=$1;}
822 	| '{' datalist '}' {$$=builddatasublist($2);}
823 	;
824 
825 constdata:
826 	  simpleconstant      {$$=$1;}
827 	| OPAQUESTRING	{$$=makeconstdata(NC_OPAQUE);}
828 	| FILLMARKER	{$$=makeconstdata(NC_FILLVALUE);}
829 	| NIL   	{$$=makeconstdata(NC_NIL);}
830 	| econstref	{$$=$1;}
831 	| function
832 	;
833 
834 econstref:
835 	path {$$ = makeenumconstref($1);}
836 	;
837 
838 function:
839 	ident '(' arglist ')' {$$=evaluate($1,$3);}
840 	;
841 
842 arglist:
843 	  simpleconstant
844 	    {$$ = const2list($1);}
845 	| arglist ',' simpleconstant
846 	    {dlappend($1,($3)); $$=$1;}
847 	;
848 
849 simpleconstant:
850 	  CHAR_CONST	{$$=makeconstdata(NC_CHAR);} /* never used apparently*/
851 	| BYTE_CONST	{$$=makeconstdata(NC_BYTE);}
852 	| SHORT_CONST	{$$=makeconstdata(NC_SHORT);}
853 	| INT_CONST	{$$=makeconstdata(NC_INT);}
854 	| INT64_CONST	{$$=makeconstdata(NC_INT64);}
855 	| UBYTE_CONST	{$$=makeconstdata(NC_UBYTE);}
856 	| USHORT_CONST	{$$=makeconstdata(NC_USHORT);}
857 	| UINT_CONST	{$$=makeconstdata(NC_UINT);}
858 	| UINT64_CONST	{$$=makeconstdata(NC_UINT64);}
859 	| FLOAT_CONST	{$$=makeconstdata(NC_FLOAT);}
860 	| DOUBLE_CONST	{$$=makeconstdata(NC_DOUBLE);}
861 	| TERMSTRING	{$$=makeconstdata(NC_STRING);}
862 	;
863 
864 intlist:
865 	  constint {$$ = const2list($1);}
866 	| intlist ',' constint {$$=$1; dlappend($1,($3));}
867 	;
868 
869 constint:
870 	  INT_CONST
871 		{$$=makeconstdata(NC_INT);}
872 	| UINT_CONST
873 		{$$=makeconstdata(NC_UINT);}
874 	| INT64_CONST
875 		{$$=makeconstdata(NC_INT64);}
876 	| UINT64_CONST
877 		{$$=makeconstdata(NC_UINT64);}
878 	;
879 
880 conststring:
881 	TERMSTRING	{$$=makeconstdata(NC_STRING);}
882 	;
883 
884 constbool:
885 	  conststring {$$=$1;}
886 	| constint {$$=$1;}
887 
888 /* End OF RULES */
889 
890 /* Push all idents thru here*/
891 ident:
892 	IDENT {$$=$1;}
893 	;
894 
895 %%
896 
897 #ifndef NO_STDARG
898 static void
899 yyerror(const char *fmt, ...)
900 #else
901 static void
902 yyerror(fmt,va_alist) const char* fmt; va_dcl
903 #endif
904 {
905     va_list argv;
906     va_start(argv,fmt);
907     (void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lineno);
908     vderror(fmt,argv);
909     va_end(argv);
910 }
911 
912 /* undefine yywrap macro, in case we are using bison instead of yacc */
913 #ifdef yywrap
914 #undef yywrap
915 #endif
916 
917 static int
ncgwrap(void)918 ncgwrap(void)                    /* returns 1 on EOF if no more input */
919 {
920     return  1;
921 }
922 
923 /* get lexical input routine generated by lex  */
924 #include "ncgenl.c"
925 
926 /* Really should init our data within this file */
927 void
parse_init(void)928 parse_init(void)
929 {
930     int i;
931     opaqueid = 0;
932     arrayuid = 0;
933     symlist = listnew();
934     stack = listnew();
935     groupstack = listnew();
936     consttype = NC_NAT;
937     grpdefs = listnew();
938     dimdefs = listnew();
939     attdefs = listnew();
940     gattdefs = listnew();
941     xattdefs = listnew();
942     typdefs = listnew();
943     vardefs = listnew();
944     condefs = listnew();
945     tmp = listnew();
946     /* Create the primitive types */
947     for(i=NC_NAT+1;i<=NC_STRING;i++) {
948         primsymbols[i] = makeprimitivetype(i);
949     }
950     lex_init();
951 }
952 
953 static Symbol*
makeprimitivetype(nc_type nctype)954 makeprimitivetype(nc_type nctype)
955 {
956     Symbol* sym = install(primtypenames[nctype]);
957     sym->objectclass=NC_TYPE;
958     sym->subclass=NC_PRIM;
959     sym->nc_id = nctype;
960     sym->typ.typecode = nctype;
961     sym->typ.size = ncsize(nctype);
962     sym->typ.nelems = 1;
963     sym->typ.alignment = ncaux_class_alignment(nctype);
964     /* Make the basetype circular so we can always ask for it */
965     sym->typ.basetype = sym;
966     sym->prefix = listnew();
967     return sym;
968 }
969 
970 /* Symbol table operations for ncgen tool */
971 /* install sname in symbol table even if it is already there */
972 Symbol*
install(const char * sname)973 install(const char *sname)
974 {
975     Symbol* sp;
976     sp = (Symbol*) ecalloc (sizeof (struct Symbol));
977     sp->name = nulldup(sname);
978     sp->lineno = lineno;
979     sp->location = currentgroup();
980     sp->container = currentgroup();
981     listpush(symlist,sp);
982     return sp;
983 }
984 
985 static Symbol*
currentgroup(void)986 currentgroup(void)
987 {
988     if(listlength(groupstack) == 0) return rootgroup;
989     return (Symbol*)listtop(groupstack);
990 }
991 
992 static Symbol*
createrootgroup(const char * dataset)993 createrootgroup(const char* dataset)
994 {
995     Symbol* gsym = install(dataset);
996     gsym->objectclass = NC_GRP;
997     gsym->container = NULL;
998     gsym->subnodes = listnew();
999     gsym->grp.is_root = 1;
1000     gsym->prefix = listnew();
1001     listpush(grpdefs,(void*)gsym);
1002     rootgroup = gsym;
1003     return gsym;
1004 }
1005 
1006 static Symbol*
creategroup(Symbol * gsym)1007 creategroup(Symbol * gsym)
1008 {
1009     /* See if this group already exists in currentgroup */
1010     gsym->objectclass = NC_GRP;
1011     if(dupobjectcheck(NC_GRP,gsym)) {
1012         derror("Duplicate group name in same scope: %s",gsym->name);
1013 	return NULL;
1014     }
1015     addtogroup(gsym);
1016     gsym->subnodes = listnew();
1017     listpush(groupstack,(void*)gsym);
1018     listpush(grpdefs,(void*)gsym);
1019     return gsym;
1020 }
1021 
1022 static NCConstant*
makeconstdata(nc_type nctype)1023 makeconstdata(nc_type nctype)
1024 {
1025     NCConstant* con = nullconst();
1026     consttype = nctype;
1027     con->nctype = nctype;
1028     con->lineno = lineno;
1029     con->filled = 0;
1030     switch (nctype) {
1031 	case NC_CHAR: con->value.charv = char_val; break;
1032         case NC_BYTE: con->value.int8v = byte_val; break;
1033         case NC_SHORT: con->value.int16v = int16_val; break;
1034         case NC_INT: con->value.int32v = int32_val; break;
1035         case NC_FLOAT:
1036 	    con->value.floatv = float_val;
1037 	    break;
1038         case NC_DOUBLE:
1039 	    con->value.doublev = double_val;
1040 	    break;
1041         case NC_STRING: { /* convert to a set of chars*/
1042 	    size_t len;
1043 	    len = bbLength(lextext);
1044 	    con->value.stringv.len = len;
1045 	    con->value.stringv.stringv = bbExtract(lextext);
1046 	    }
1047 	    break;
1048 
1049 	/* Allow these constants even in netcdf-3 */
1050         case NC_UBYTE: con->value.uint8v = ubyte_val; break;
1051         case NC_USHORT: con->value.uint16v = uint16_val; break;
1052         case NC_UINT: con->value.uint32v = uint32_val; break;
1053         case NC_INT64: con->value.int64v = int64_val; break;
1054         case NC_UINT64: con->value.uint64v = uint64_val; break;
1055 
1056 #ifdef USE_NETCDF4
1057 	case NC_OPAQUE: {
1058 	    char* s;
1059 	    int len;
1060 	    len = bbLength(lextext);
1061 	    s = (char*)ecalloc(len+1);
1062 	    strncpy(s,bbContents(lextext),len);
1063 	    s[len] = '\0';
1064 	    con->value.opaquev.stringv = s;
1065 	    con->value.opaquev.len = len;
1066 	    } break;
1067 
1068 	case NC_NIL:
1069 	    break; /* no associated value*/
1070 #endif
1071 
1072  	case NC_FILLVALUE:
1073 	    break; /* no associated value*/
1074 
1075 	default:
1076 	    yyerror("Data constant: unexpected NC type: %s",
1077 		    nctypename(nctype));
1078 	    con->value.stringv.stringv = NULL;
1079 	    con->value.stringv.len = 0;
1080     }
1081     return con;
1082 }
1083 
1084 static NCConstant*
makeenumconstref(Symbol * refsym)1085 makeenumconstref(Symbol* refsym)
1086 {
1087     NCConstant* con = nullconst();
1088 
1089     markcdf4("Enum type");
1090     consttype = NC_ENUM;
1091     con->nctype = NC_ECONST;
1092     con->lineno = lineno;
1093     con->filled = 0;
1094     refsym->objectclass = NC_TYPE;
1095     refsym->subclass = NC_ECONST;
1096     con->value.enumv = refsym;
1097     return con;
1098 }
1099 
1100 static void
addtogroup(Symbol * sym)1101 addtogroup(Symbol* sym)
1102 {
1103     Symbol* grp = currentgroup();
1104     sym->container = grp;
1105     listpush(grp->subnodes,(void*)sym);
1106     setpathcurrent(sym);
1107 }
1108 
1109 /* Check for duplicate name of given type within current group*/
1110 static int
dupobjectcheck(nc_class objectclass,Symbol * pattern)1111 dupobjectcheck(nc_class objectclass, Symbol* pattern)
1112 {
1113     int i;
1114     Symbol* grp;
1115     if(pattern == NULL) return 0;
1116     grp = pattern->container;
1117     if(grp == NULL || grp->subnodes == NULL) return 0;
1118     for(i=0;i<listlength(grp->subnodes);i++) {
1119 	Symbol* sym = (Symbol*)listget(grp->subnodes,i);
1120 	if(!sym->ref.is_ref && sym->objectclass == objectclass
1121 	   && strcmp(sym->name,pattern->name)==0) return 1;
1122     }
1123     return 0;
1124 }
1125 
1126 static void
setpathcurrent(Symbol * sym)1127 setpathcurrent(Symbol* sym)
1128 {
1129     sym->is_prefixed = 0;
1130     sym->prefix = prefixdup(groupstack);
1131 }
1132 
1133 /* Convert an nc_type code to the corresponding Symbol*/
1134 Symbol*
basetypefor(nc_type nctype)1135 basetypefor(nc_type nctype)
1136 {
1137     return primsymbols[nctype];
1138 }
1139 
1140 static int
truefalse(NCConstant * con,int tag)1141 truefalse(NCConstant* con, int tag)
1142 {
1143     if(con->nctype == NC_STRING) {
1144 	char* sdata = con->value.stringv.stringv;
1145 	if(strncmp(sdata,"false",NC_MAX_NAME) == 0
1146            || strncmp(sdata,"0",NC_MAX_NAME) == 0)
1147 	    return 0;
1148 	else if(strncmp(sdata,"true",NC_MAX_NAME) == 0
1149            || strncmp(sdata,"1",NC_MAX_NAME) == 0)
1150 	    return 1;
1151 	else goto fail;
1152     } else if(con->value.int32v < 0 || con->value.int32v > 1)
1153 	goto fail;
1154     return con->value.int32v;
1155 
1156 fail:
1157     derror("%s: illegal value",specialname(tag));
1158     return 0;
1159 }
1160 
1161 /* Since this may be affected by the _Format attribute, which
1162    may come last, capture all the special info and sort it out
1163    in semantics.
1164 */
1165 static Symbol*
makespecial(int tag,Symbol * vsym,Symbol * tsym,void * data,int isconst)1166 makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst)
1167 {
1168     Symbol* attr = NULL;
1169     Datalist* list = NULL;
1170     NCConstant* con = NULL;
1171     NCConstant* tmp = NULL;
1172     int tf = 0;
1173     char* sdata = NULL;
1174     int idata =  -1;
1175 
1176     if((GLOBAL_SPECIAL & tag) != 0) {
1177         if(vsym != NULL) {
1178             derror("_Format: must be global attribute");
1179             vsym = NULL;
1180         }
1181     } else {
1182         if(vsym == NULL) {
1183 	    derror("%s: must have non-NULL vsym", specialname(tag));
1184 	    return NULL;
1185         }
1186     }
1187 
1188     if(tag != _FILLVALUE_FLAG && tag != _FORMAT_FLAG)
1189         /*Main.*/specials_flag++;
1190 
1191     if(isconst)
1192 	con = (NCConstant*)data;
1193     else
1194         list = (Datalist*)data;
1195 
1196     switch (tag) {
1197     case _FLETCHER32_FLAG:
1198     case _SHUFFLE_FLAG:
1199     case _ISNETCDF4_FLAG:
1200     case _NOFILL_FLAG:
1201 	tmp = nullconst();
1202 	tmp->nctype = (con->nctype == NC_STRING?NC_STRING:NC_INT);
1203 	convert1(con,tmp);
1204 	tf = truefalse(tmp,tag);
1205 	reclaimconstant(tmp);
1206 	break;
1207     case _FORMAT_FLAG:
1208     case _STORAGE_FLAG:
1209     case _NCPROPS_FLAG:
1210     case _ENDIAN_FLAG:
1211     case _FILTER_FLAG:
1212 	tmp = nullconst();
1213         tmp->nctype = NC_STRING;
1214 	convert1(con,tmp);
1215 	if(tmp->nctype == NC_STRING) {
1216 	    sdata = tmp->value.stringv.stringv;
1217 	    tmp->value.stringv.stringv = NULL;
1218 	    tmp->value.stringv.len = 0;
1219 	} else
1220 	    derror("%s: illegal value",specialname(tag));
1221 	reclaimconstant(tmp);
1222 	break;
1223     case _SUPERBLOCK_FLAG:
1224     case _DEFLATE_FLAG:
1225 	tmp = nullconst();
1226         tmp->nctype = NC_INT;
1227 	convert1(con,tmp);
1228 	if(tmp->nctype == NC_INT)
1229 	    idata = tmp->value.int32v;
1230 	else
1231 	    derror("%s: illegal value",specialname(tag));
1232 	reclaimconstant(tmp);
1233 	break;
1234     case _CHUNKSIZES_FLAG:
1235     case _FILLVALUE_FLAG:
1236 	/* Handle below */
1237 	break;
1238     default: PANIC1("unexpected special tag: %d",tag);
1239     }
1240 
1241     if(tag == _FORMAT_FLAG) {
1242 	/* Watch out: this is a global attribute */
1243 	struct Kvalues* kvalue;
1244 	int found = 0;
1245 	/* Use the table in main.c */
1246         for(kvalue = legalkinds; kvalue->name; kvalue++) {
1247           if(sdata) {
1248             if(strcmp(sdata, kvalue->name) == 0) {
1249               globalspecials._Format = kvalue->k_flag;
1250 	      /*Main.*/format_attribute = 1;
1251               found = 1;
1252               break;
1253             }
1254           }
1255 	}
1256 	if(!found)
1257 	    derror("_Format: illegal value: %s",sdata);
1258     } else if((GLOBAL_SPECIAL & tag) != 0) {
1259 	if(tag == _ISNETCDF4_FLAG)
1260 	    globalspecials._IsNetcdf4 = tf;
1261 	else if(tag == _SUPERBLOCK_FLAG)
1262 	    globalspecials._Superblock = idata;
1263 	else if(tag == _NCPROPS_FLAG) {
1264 	    globalspecials._NCProperties = sdata;
1265 	    sdata = NULL;
1266 	}
1267     } else {
1268         Specialdata* special;
1269         /* Set up special info */
1270 	if(vsym->var.special == NULL) {
1271             vsym->var.special = ecalloc(sizeof(Specialdata));
1272 	    if(vsym->var.special == NULL)
1273 	        derror("Out of memory");
1274 	}
1275         special = vsym->var.special;
1276         if(tag == _FILLVALUE_FLAG) {
1277             /* fillvalue must be a single value*/
1278 	    if(!isconst && datalistlen(list) != 1)
1279                 derror("_FillValue: must be a single (possibly compound) value",
1280                             vsym->name);
1281 	    if(isconst) {
1282 	        list = const2list(con);
1283 		con = NULL;
1284 	    }
1285             /* check that the attribute value contains no fill values*/
1286             if(containsfills(list)) {
1287                 derror("Attribute data may not contain fill values (i.e. _ )");
1288             }
1289             /* _FillValue is also a real attribute*/
1290             if(vsym->objectclass != NC_VAR) {
1291                 derror("_FillValue attribute not associated with variable: %s",vsym->name);
1292             }
1293             if(tsym  == NULL) tsym = vsym->typ.basetype;
1294             else if(vsym->typ.basetype != tsym) {
1295                 derror("_FillValue attribute type does not match variable type: %s",vsym->name);
1296             }
1297             special->_Fillvalue = clonedatalist(list);
1298 	    /* Create the corresponding attribute */
1299             attr = makeattribute(install("_FillValue"),vsym,tsym,list,ATTRVAR);
1300 	    list = NULL;
1301         } else switch (tag) {
1302 	    /* These will be output as attributes later */
1303             case _STORAGE_FLAG:
1304               if(!sdata)
1305                 derror("_Storage: illegal NULL value");
1306               else if(strcmp(sdata,"contiguous") == 0)
1307                 special->_Storage = NC_CONTIGUOUS;
1308               else if(strcmp(sdata,"compact") == 0)
1309                 special->_Storage = NC_COMPACT;
1310               else if(strcmp(sdata,"chunked") == 0)
1311                 special->_Storage = NC_CHUNKED;
1312               else
1313                 derror("_Storage: illegal value: %s",sdata);
1314               special->flags |= _STORAGE_FLAG;
1315               break;
1316           case _FLETCHER32_FLAG:
1317                 special->_Fletcher32 = tf;
1318                 special->flags |= _FLETCHER32_FLAG;
1319                 break;
1320             case _DEFLATE_FLAG:
1321                 special->_DeflateLevel = idata;
1322                 special->flags |= _DEFLATE_FLAG;
1323                 break;
1324             case _SHUFFLE_FLAG:
1325                 special->_Shuffle = tf;
1326                 special->flags |= _SHUFFLE_FLAG;
1327                 break;
1328             case _ENDIAN_FLAG:
1329               if(!sdata)
1330                 derror("_Endianness: illegal NULL value");
1331               else if(strcmp(sdata,"little") == 0)
1332                 special->_Endianness = 1;
1333               else if(strcmp(sdata,"big") == 0)
1334                 special->_Endianness = 2;
1335               else
1336                 derror("_Endianness: illegal value: %s",sdata);
1337               special->flags |= _ENDIAN_FLAG;
1338               break;
1339           case _NOFILL_FLAG:
1340                 special->_Fill = (1 - tf); /* negate */
1341                 special->flags |= _NOFILL_FLAG;
1342                 break;
1343           case _CHUNKSIZES_FLAG: {
1344                 int i;
1345 		list = (isconst ? const2list(con) : list);
1346                 special->nchunks = list->length;
1347                 special->_ChunkSizes = (size_t*)ecalloc(sizeof(size_t)*special->nchunks);
1348                 for(i=0;i<special->nchunks;i++) {
1349 		    tmp = nullconst();
1350                     tmp->nctype = NC_INT;
1351                     convert1(list->data[i],tmp);
1352                     if(tmp->nctype == NC_INT) {
1353                         special->_ChunkSizes[i] = (size_t)tmp->value.int32v;
1354                     } else {
1355                         efree(special->_ChunkSizes);
1356                         derror("%s: illegal value",specialname(tag));
1357                     }
1358 		    reclaimconstant(tmp);
1359                 }
1360                 special->flags |= _CHUNKSIZES_FLAG;
1361                 /* Chunksizes => storage == chunked */
1362                 special->flags |= _STORAGE_FLAG;
1363                 special->_Storage = NC_CHUNKED;
1364                 } break;
1365           case _FILTER_FLAG:
1366 #ifdef USE_NETCDF4
1367 		/* Parse the filter spec */
1368 		if(parsefilterflag(sdata,special) == NC_NOERR)
1369                     special->flags |= _FILTER_FLAG;
1370 		else {
1371 		    derror("_Filter: unparsable filter spec: %s",sdata);
1372 		}
1373 #else
1374 	        derror("%s: the filter attribute requires netcdf-4 to be enabled",specialname(tag));
1375 #endif
1376                 break;
1377             default: PANIC1("makespecial: illegal token: %d",tag);
1378          }
1379     }
1380     if(sdata) efree(sdata);
1381     if(con) reclaimconstant(con);
1382     if(list) reclaimdatalist(list);
1383     return attr;
1384 }
1385 
1386 static Symbol*
makeattribute(Symbol * asym,Symbol * vsym,Symbol * tsym,Datalist * data,Attrkind kind)1387 makeattribute(Symbol* asym,
1388 		Symbol* vsym,
1389 		Symbol* tsym,
1390 		Datalist* data,
1391 		Attrkind kind) /* global var or unknown*/
1392 {
1393     asym->objectclass = NC_ATT;
1394     asym->data = data;
1395     switch (kind) {
1396     case ATTRVAR:
1397         asym->att.var = vsym;
1398         asym->typ.basetype = tsym;
1399         listpush(attdefs,(void*)asym);
1400         addtogroup(asym);
1401 	break;
1402     case ATTRGLOBAL:
1403         asym->att.var = NULL; /* NULL => NC_GLOBAL*/
1404         asym->typ.basetype = tsym;
1405         listpush(gattdefs,(void*)asym);
1406         addtogroup(asym);
1407 	break;
1408     default: PANIC1("unexpected attribute type: %d",kind);
1409     }
1410     /* finally; check that the attribute value contains no fill values*/
1411     if(containsfills(data)) {
1412 	derror("Attribute data may not contain fill values (i.e. _ ): %s",asym->name);
1413     }
1414     return asym;
1415 }
1416 
1417 static long long
extractint(NCConstant * con)1418 extractint(NCConstant* con)
1419 {
1420     switch (con->nctype) {
1421     case NC_BYTE: return (long long)(con->value.int8v);
1422     case NC_SHORT: return (long long)(con->value.int16v);
1423     case NC_INT: return (long long)(con->value.int32v);
1424     case NC_UBYTE: return (long long)(con->value.uint8v);
1425     case NC_USHORT: return (long long)(con->value.uint16v);
1426     case NC_UINT: return (long long)(con->value.uint32v);
1427     case NC_INT64: return (long long)(con->value.int64v);
1428     default:
1429 	derror("Not a signed integer type: %d",con->nctype);
1430 	break;
1431     }
1432     return 0;
1433 }
1434 
1435 static int
containsfills(Datalist * list)1436 containsfills(Datalist* list)
1437 {
1438     if(list != NULL) {
1439         int i;
1440         NCConstant** cons = list->data;
1441         for(i=0;i<list->length;i++) {
1442 	    if(cons[i]->nctype == NC_COMPOUND) {
1443 	        if(containsfills(cons[i]->value.compoundv)) return 1;
1444 	    } else if(cons[i]->nctype == NC_FILLVALUE)
1445 		return 1;
1446 	}
1447     }
1448     return 0;
1449 }
1450 
1451 /*
1452 Try to infer the file type from the
1453 kinds of constructs used in the cdl file.
1454 */
1455 static void
vercheck(int tid)1456 vercheck(int tid)
1457 {
1458     switch (tid) {
1459     case NC_UBYTE: markcdf4("netCDF4/5 type: UBYTE"); break;
1460     case NC_USHORT: markcdf4("netCDF4/5 type: USHORT"); break;
1461     case NC_UINT: markcdf4("netCDF4/5 type: UINT"); break;
1462     case NC_INT64: markcdf4("netCDF4/5 type: INT64"); break;
1463     case NC_UINT64: markcdf4("netCDF4/5 type: UINT64"); break;
1464     case NC_STRING: markcdf4("netCDF4 type: STRING"); break;
1465     case NC_VLEN: markcdf4("netCDF4 type: VLEN"); break;
1466     case NC_OPAQUE: markcdf4("netCDF4 type: OPAQUE"); break;
1467     case NC_ENUM: markcdf4("netCDF4 type: ENUM"); break;
1468     case NC_COMPOUND: markcdf4("netCDF4 type: COMPOUND"); break;
1469     default: break;
1470     }
1471 }
1472 
1473 const char*
specialname(int tag)1474 specialname(int tag)
1475 {
1476     struct Specialtoken* spp = specials;
1477     for(;spp->name;spp++) {
1478 	if(spp->tag == tag)
1479 	    return spp->name;
1480     }
1481     return "<unknown>";
1482 }
1483 
1484 #ifdef USE_NETCDF4
1485 /*
1486 Parse a filter spec string and store it in special
1487 */
1488 static int
parsefilterflag(const char * sdata,Specialdata * special)1489 parsefilterflag(const char* sdata, Specialdata* special)
1490 {
1491     int stat = NC_NOERR;
1492     int format;
1493 
1494     if(sdata == NULL || strlen(sdata) == 0) return NC_EINVAL;
1495 
1496     stat = NC_parsefilterlist(sdata, &format, &special->nfilters, (NC_Filterspec***)&special->_Filters);
1497     if(stat)
1498         derror("Malformed filter spec: %s",sdata);
1499     if(format != NC_FILTER_FORMAT_HDF5)
1500         derror("Non HDF5 filter format encountered");
1501 #ifdef GENDEBUG1
1502 printfilters(special->nfilters,special->_Filters);
1503 #endif
1504     return stat;
1505 }
1506 #endif
1507 
1508 /*
1509 Since the arguments are all simple constants,
1510 we can evaluate the function immediately
1511 and return its value.
1512 Note that currently, only a single value can
1513 be returned.
1514 */
1515 
1516 static NCConstant*
evaluate(Symbol * fcn,Datalist * arglist)1517 evaluate(Symbol* fcn, Datalist* arglist)
1518 {
1519     NCConstant* result = nullconst();
1520 
1521     /* prepare the result */
1522     result->lineno = fcn->lineno;
1523 
1524     if(strcasecmp(fcn->name,"time") == 0) {
1525         char* timekind = NULL;
1526         char* timevalue = NULL;
1527         result->nctype = NC_DOUBLE;
1528         result->value.doublev = 0;
1529 	/* int time([string],string) */
1530 	switch (arglist->length) {
1531 	case 2:
1532 	    if(arglist->data[1]->nctype != NC_STRING) {
1533 	        derror("Expected function signature: time([string,]string)");
1534 	        goto done;
1535 	    }
1536 	    /* fall thru */
1537 	case 1:
1538 	    if(arglist->data[0]->nctype != NC_STRING) {
1539 	        derror("Expected function signature: time([string,]string)");
1540 	        goto done;
1541 	    }
1542 	    break;
1543 	case 0:
1544 	default:
1545 	    derror("Expected function signature: time([string,]string)");
1546 	    goto done;
1547 	}
1548 	if(arglist->length == 2) {
1549 	    timekind = arglist->data[0]->value.stringv.stringv;
1550             timevalue = arglist->data[1]->value.stringv.stringv;
1551 	} else
1552             timevalue = arglist->data[0]->value.stringv.stringv;
1553 	if(timekind == NULL) { /* use cd time as the default */
1554             cdCompTime comptime;
1555 	    CdTime cdtime;
1556 	    cdCalenType timetype = cdStandard;
1557 	    cdChar2Comp(timetype,timevalue,&comptime);
1558 	    /* convert comptime to cdTime */
1559 	    cdtime.year = comptime.year;
1560 	    cdtime.month = comptime.month;
1561 	    cdtime.day = comptime.day;
1562 	    cdtime.hour = comptime.hour;
1563 	    cdtime.baseYear = 1970;
1564 	    cdtime.timeType = CdChron;
1565 	    /* convert to double value */
1566 	    Cdh2e(&cdtime,&result->value.doublev);
1567         } else {
1568 	    derror("Time conversion '%s' not supported",timekind);
1569 	    goto done;
1570 	}
1571     } else {	/* Unknown function */
1572 	derror("Unknown function name: %s",fcn->name);
1573 	goto done;
1574     }
1575 
1576 done:
1577     return result;
1578 }
1579 
1580 #ifdef GENDEBUG1
1581 static void
printfilters(size_t nfilters,NC_ParsedFilterSpec ** filters)1582 printfilters(size_t nfilters, NC_ParsedFilterSpec** filters)
1583 {
1584     int i;
1585     fprintf(stderr,"xxx: nfilters=%lu: ",(unsigned long)nfilters);
1586     for(i=0;i<nfilters;i++) {
1587 	int k;
1588 	NC_ParsedFilterSpec* sp = filters[i];
1589         fprintf(stderr,"{");
1590         fprintf(stderr,"filterid=%llu format=%d nparams=%lu params=%p",
1591 		sp->filterid,sp->format,(unsigned long)sp->nparams,sp->params);
1592 	if(sp->nparams == 0 || sp->params != NULL) {
1593             fprintf(stderr," params={");
1594             for(k=0;k<sp->nparams;k++) {
1595 	        if(i==0) fprintf(stderr,",");
1596 	        fprintf(stderr,"%u",sp->params[i]);
1597 	    }
1598             fprintf(stderr,"}");
1599 	} else
1600             fprintf(stderr,"params=NULL");
1601         fprintf(stderr,"}");
1602     }
1603     fprintf(stderr,"\n");
1604     fflush(stderr);
1605 }
1606 #endif
1607