1 /*********************************************************************
2 * Copyright 2018, UCAR/Unidata
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 * $Header: /upc/share/CVS/netcdf-3/ncgen/util.c,v 1.4 2010/04/14 22:04:59 dmh Exp $
5 *********************************************************************/
6
7 #include "includes.h"
8
9 /* Track primitive symbol instances (initialized in ncgen.y) */
10 Symbol* primsymbols[PRIMNO];
11
12 char*
append(const char * s1,const char * s2)13 append(const char* s1, const char* s2)
14 {
15 int len = (s1?strlen(s1):0)+(s2?strlen(s2):0);
16 char* result = (char*)ecalloc(len+1);
17 result[0] = '\0';
18 if(s1) strcat(result,s1);
19 if(s2) strcat(result,s2);
20 return result;
21 }
22
23
24 unsigned int
chartohex(char c)25 chartohex(char c)
26 {
27 switch (c) {
28 case '0': case '1': case '2': case '3': case '4':
29 case '5': case '6': case '7': case '8': case '9':
30 return (c - '0');
31 case 'A': case 'B': case 'C':
32 case 'D': case 'E': case 'F':
33 return (c - 'A') + 0x0a;
34 case 'a': case 'b': case 'c':
35 case 'd': case 'e': case 'f':
36 return (c - 'a') + 0x0a;
37 }
38 return 0;
39 }
40
41 /*
42 * For generated Fortran, change 'e' to 'd' in exponent of double precision
43 * constants.
44 */
45 void
expe2d(char * cp)46 expe2d(
47 char *cp) /* string containing double constant */
48 {
49 char *expchar = strrchr(cp,'e');
50 if (expchar) {
51 *expchar = 'd';
52 }
53 }
54
55 /* Returns non-zero if n is a power of 2, 0 otherwise */
56 int
pow2(int n)57 pow2(
58 int n)
59 {
60 int m = n;
61 int p = 1;
62
63 while (m > 0) {
64 m /= 2;
65 p *= 2;
66 }
67 return p == 2*n;
68 }
69
70
71 /*
72 * Remove trailing zeros (after decimal point) but not trailing decimal
73 * point from ss, a string representation of a floating-point number that
74 * might include an exponent part.
75 */
76 void
tztrim(char * ss)77 tztrim(
78 char *ss /* returned string representing dd */
79 )
80 {
81 char *cp, *ep;
82
83 cp = ss;
84 if (*cp == '-')
85 cp++;
86 while(isdigit((int)*cp) || *cp == '.')
87 cp++;
88 if (*--cp == '.')
89 return;
90 ep = cp+1;
91 while (*cp == '0')
92 cp--;
93 cp++;
94 if (cp == ep)
95 return;
96 while (*ep)
97 *cp++ = *ep++;
98 *cp = '\0';
99 return;
100 }
101
102 #if 0
103 /* Assume bytebuffer contains pointers to char**/
104 void
105 reclaimattptrs(void* buf, long count)
106 {
107 int i;
108 char** ptrs = (char**)buf;
109 for(i=0;i<count;i++) {efree((void*)ptrs[i]);}
110 }
111 #endif
112
113 static void
freeSpecialdata(Specialdata * data)114 freeSpecialdata(Specialdata* data)
115 {
116 if(data == NULL) return;
117 reclaimdatalist(data->_Fillvalue);
118 if(data->_ChunkSizes)
119 efree(data->_ChunkSizes);
120 if(data->_Filters) {
121 int i;
122 for(i=0;i<data->nfilters;i++) {
123 NC4_Filterspec* f = (NC4_Filterspec*)data->_Filters[i];
124 efree(f->params);
125 efree(f);
126 }
127 efree(data->_Filters);
128 }
129 efree(data);
130 }
131
132 void
freeSymbol(Symbol * sym)133 freeSymbol(Symbol* sym)
134 {
135 /* recurse first */
136 switch (sym->objectclass) {
137 case NC_VAR:
138 freeSpecialdata(sym->var.special);
139 listfree(sym->var.attributes);
140 break;
141 case NC_TYPE:
142 if(sym->typ.econst)
143 reclaimconstant(sym->typ.econst);
144 if(sym->typ._Fillvalue)
145 reclaimdatalist(sym->typ._Fillvalue);
146 break;
147 case NC_GRP:
148 if(sym->file.filename)
149 efree(sym->file.filename);
150 break;
151 default: break;
152 }
153 /* Universal */
154 if(sym->name) efree(sym->name);
155 if(sym->fqn) efree(sym->fqn);
156 listfree(sym->prefix);
157 if(sym->data)
158 reclaimdatalist(sym->data);
159 listfree(sym->subnodes);
160 efree(sym);
161 }
162
163 char* nctypenames[17] = {
164 "NC_NAT",
165 "NC_BYTE", "NC_CHAR", "NC_SHORT", "NC_INT",
166 "NC_FLOAT", "NC_DOUBLE",
167 "NC_UBYTE", "NC_USHORT", "NC_UINT",
168 "NC_INT64", "NC_UINT64",
169 "NC_STRING",
170 "NC_VLEN", "NC_OPAQUE", "NC_ENUM", "NC_COMPOUND"
171 };
172
173 char* nctypenamesextend[9] = {
174 "NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT", "NC_TYPE",
175 "NC_ECONST","NC_FIELD", "NC_ARRAY","NC_PRIM"
176 };
177
178 char*
nctypename(nc_type nctype)179 nctypename(nc_type nctype)
180 {
181 char* s;
182 if(nctype >= NC_NAT && nctype <= NC_COMPOUND)
183 return nctypenames[nctype];
184 if(nctype >= NC_GRP && nctype <= NC_PRIM)
185 return nctypenamesextend[(nctype - NC_GRP)];
186 if(nctype == NC_FILLVALUE) return "NC_FILL";
187 if(nctype == NC_NIL) return "NC_NIL";
188 s = poolalloc(128);
189 sprintf(s,"NC_<%d>",nctype);
190 return s;
191 }
192
193 /* These are the augmented NC_ values (0 based from NC_GRP)*/
194 char* ncclassnames[9] = {
195 "NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT",
196 "NC_TYP", "NC_ECONST", "NC_FIELD", "NC_ARRAY",
197 "NC_PRIM"
198 };
199
200 char*
ncclassname(nc_class ncc)201 ncclassname(nc_class ncc)
202 {
203 char* s;
204 if(ncc >= NC_NAT && ncc <= NC_COMPOUND)
205 return nctypename((nc_type)ncc);
206 if(ncc == NC_FILLVALUE) return "NC_FILL";
207 if(ncc >= NC_GRP && ncc <= NC_PRIM)
208 return ncclassnames[ncc - NC_GRP];
209 s = poolalloc(128);
210 sprintf(s,"NC_<%d>",ncc);
211 return s;
212 }
213
214 int ncsizes[17] = {
215 0,
216 1,1,2,4,
217 4,8,
218 1,2,4,
219 8,8,
220 sizeof(char*),
221 sizeof(nc_vlen_t),
222 0,0,0
223 };
224
225 int
ncsize(nc_type nctype)226 ncsize(nc_type nctype)
227 {
228 if(nctype >= NC_NAT && nctype <= NC_COMPOUND)
229 return ncsizes[nctype];
230 return 0;
231 }
232
233 int
hasunlimited(Dimset * dimset)234 hasunlimited(Dimset* dimset)
235 {
236 int i;
237 for(i=0;i<dimset->ndims;i++) {
238 Symbol* dim = dimset->dimsyms[i];
239 if(dim->dim.declsize == NC_UNLIMITED) return 1;
240 }
241 return 0;
242 }
243
244 /* return 1 if first dimension is unlimited*/
245 int
isunlimited0(Dimset * dimset)246 isunlimited0(Dimset* dimset)
247 {
248 return (dimset->ndims > 0 && dimset->dimsyms[0]->dim.declsize == NC_UNLIMITED);
249 }
250
251
252 /* True only if dim[0] is unlimited all rest are bounded*/
253 /* or all are bounded*/
254 int
classicunlimited(Dimset * dimset)255 classicunlimited(Dimset* dimset)
256 {
257 int i;
258 int last = -1;
259 for(i=0;i<dimset->ndims;i++) {
260 Symbol* dim = dimset->dimsyms[i];
261 if(dim->dim.declsize == NC_UNLIMITED) last = i;
262 }
263 return (last < 1);
264 }
265
266 /* True only iff no dimension is unlimited*/
267 int
isbounded(Dimset * dimset)268 isbounded(Dimset* dimset)
269 {
270 int i;
271 for(i=0;i<dimset->ndims;i++) {
272 Symbol* dim = dimset->dimsyms[i];
273 if(dim->dim.declsize == NC_UNLIMITED) return 0;
274 }
275 return 1;
276 }
277
278 int
signedtype(nc_type nctype)279 signedtype(nc_type nctype)
280 {
281 switch (nctype) {
282 case NC_BYTE:
283 case NC_SHORT:
284 case NC_INT:
285 case NC_INT64:
286 return nctype;
287 case NC_UBYTE: return NC_BYTE;
288 case NC_USHORT: return NC_SHORT;
289 case NC_UINT: return NC_INT;
290 case NC_UINT64: return NC_INT64;
291 default: break;
292 }
293 return nctype;
294 }
295
296 int
unsignedtype(nc_type nctype)297 unsignedtype(nc_type nctype)
298 {
299 switch (nctype) {
300 case NC_UBYTE:
301 case NC_USHORT:
302 case NC_UINT:
303 case NC_UINT64:
304 return nctype;
305 case NC_BYTE: return NC_UBYTE;
306 case NC_SHORT: return NC_USHORT;
307 case NC_INT: return NC_UINT;
308 case NC_INT64: return NC_UINT64;
309 default: break;
310 }
311 return nctype;
312 }
313
314 int
isinttype(nc_type nctype)315 isinttype(nc_type nctype)
316 {
317 return (nctype != NC_CHAR)
318 && ((nctype >= NC_BYTE && nctype <= NC_INT)
319 || (nctype >= NC_UBYTE && nctype <= NC_UINT64));
320 }
321
322 int
isuinttype(nc_type t)323 isuinttype(nc_type t)
324 {
325 return isinttype(t)
326 && t >= NC_UBYTE
327 && t <= NC_UINT64
328 && t != NC_INT64;
329 }
330
331 int
isfloattype(nc_type nctype)332 isfloattype(nc_type nctype)
333 {
334 return (nctype == NC_FLOAT || nctype <= NC_DOUBLE);
335 }
336
337 int
isclassicprim(nc_type nctype)338 isclassicprim(nc_type nctype)
339 {
340 return (nctype >= NC_BYTE && nctype <= NC_DOUBLE)
341 ;
342 }
343
344 int
isclassicprimplus(nc_type nctype)345 isclassicprimplus(nc_type nctype)
346 {
347 return (nctype >= NC_BYTE && nctype <= NC_DOUBLE)
348 || (nctype == NC_STRING)
349 ;
350 }
351
352 int
isprim(nc_type nctype)353 isprim(nc_type nctype)
354 {
355 return (nctype >= NC_BYTE && nctype <= NC_STRING)
356 ;
357 }
358
359 int
isprimplus(nc_type nctype)360 isprimplus(nc_type nctype)
361 {
362 return (nctype >= NC_BYTE && nctype <= NC_STRING)
363 || (nctype == NC_ECONST)
364 || (nctype == NC_OPAQUE)
365 ;
366 }
367
368 void
collectpath(Symbol * grp,List * grpstack)369 collectpath(Symbol* grp, List* grpstack)
370 {
371 while(grp != NULL) {
372 listpush(grpstack,(void*)grp);
373 grp = grp->container;
374 }
375 }
376
377
378 #ifdef USE_NETCDF4
379 /* Result is pool'd*/
380 char*
prefixtostring(List * prefix,char * separator)381 prefixtostring(List* prefix, char* separator)
382 {
383 int slen=0;
384 int plen;
385 int i;
386 char* result;
387 if(prefix == NULL) return pooldup("");
388 plen = prefixlen(prefix);
389 if(plen == 0) { /* root prefix*/
390 slen=0;
391 /* slen += strlen(separator);*/
392 slen++; /* for null terminator*/
393 result = poolalloc(slen);
394 result[0] = '\0';
395 /*strcat(result,separator);*/
396 } else {
397 for(i=0;i<plen;i++) {
398 Symbol* sym = (Symbol*)listget(prefix,i);
399 slen += (strlen(separator)+strlen(sym->name));
400 }
401 slen++; /* for null terminator*/
402 result = poolalloc(slen);
403 result[0] = '\0';
404 for(i=0;i<plen;i++) {
405 Symbol* sym = (Symbol*)listget(prefix,i);
406 strcat(result,separator);
407 strcat(result,sym->name); /* append "/<prefix[i]>"*/
408 }
409 }
410 return result;
411 }
412 #endif
413
414 /* Result is pool'd*/
415 char*
fullname(Symbol * sym)416 fullname(Symbol* sym)
417 {
418 #ifdef USE_NETCDF4
419 char* s1;
420 char* result;
421 char* prefix;
422 prefix = prefixtostring(sym->prefix,PATHSEPARATOR);
423 s1 = poolcat(prefix,PATHSEPARATOR);
424 result = poolcat(s1,sym->name);
425 return result;
426 #else
427 return nulldup(sym->name);
428 #endif
429 }
430
431 int
prefixeq(List * x1,List * x2)432 prefixeq(List* x1, List* x2)
433 {
434 Symbol** l1;
435 Symbol** l2;
436 int len,i;
437 if((len=listlength(x1)) != listlength(x2)) return 0;
438 l1=(Symbol**)listcontents(x1);
439 l2=(Symbol**)listcontents(x2);
440 for(i=0;i<len;i++) {
441 if(strcmp(l1[i]->name,l2[i]->name) != 0) return 0;
442 }
443 return 1;
444 }
445
446 List*
prefixdup(List * prefix)447 prefixdup(List* prefix)
448 {
449 List* dupseq;
450 int i;
451 if(prefix == NULL) return listnew();
452 dupseq = listnew();
453 listsetalloc(dupseq,listlength(prefix));
454 for(i=0;i<listlength(prefix);i++) listpush(dupseq,listget(prefix,i));
455 return dupseq;
456 }
457
458 /*
459 Many of the generate routines need to construct
460 heap strings for short periods. Remembering to
461 free such space is error prone, so provide a
462 pseudo-GC to handle these short term requests.
463 The idea is to have a fixed size pool
464 tracking malloc requests and automatically
465 releasing when the pool gets full.
466 */
467
468 /* Max number of allocated pool items*/
469 #define POOLMAX 100
470
471 static char* pool[POOLMAX];
472 static int poolindex = -1;
473 #define POOL_DEFAULT 256
474
475 char*
poolalloc(size_t length)476 poolalloc(size_t length)
477 {
478 if(poolindex == -1) { /* initialize*/
479 memset((void*)pool,0,sizeof(pool));
480 poolindex = 0;
481 }
482 if(poolindex == POOLMAX) poolindex=0;
483 if(length == 0) length = POOL_DEFAULT;
484 if(pool[poolindex] != NULL) efree(pool[poolindex]);
485 pool[poolindex] = (char*)ecalloc(length);
486 return pool[poolindex++];
487 }
488
489 char*
pooldup(const char * s)490 pooldup(const char* s)
491 {
492 char* sdup = poolalloc(strlen(s)+1);
493 strncpy(sdup,s,(strlen(s)+1));
494 return sdup;
495 }
496
497 char*
poolcat(const char * s1,const char * s2)498 poolcat(const char* s1, const char* s2)
499 {
500 int len1, len2;
501 char* cat;
502 if(s1 == NULL && s2 == NULL) return NULL;
503 len1 = (s1?strlen(s1):0);
504 len2 = (s2?strlen(s2):0);
505 cat = poolalloc(len1+len2+1);
506 cat[0] = '\0';
507 if(s1 != NULL) strcat(cat,s1);
508 if(s2 != NULL) strcat(cat,s2);
509 return cat;
510 }
511
512 /* Result is malloc'd*/
513 unsigned char*
makebytestring(char * s,size_t * lenp)514 makebytestring(char* s, size_t* lenp)
515 {
516 unsigned char* bytes;
517 unsigned char* b;
518 size_t slen = strlen(s); /* # nibbles */
519 size_t blen = slen/2; /* # bytes */
520 int i;
521
522 ASSERT((slen%2) == 0);
523 ASSERT(blen > 0);
524 bytes = (unsigned char*)ecalloc(blen);
525 b = bytes;
526 for(i=0;i<slen;i+=2) {
527 unsigned int digit1 = chartohex(*s++);
528 unsigned int digit2 = chartohex(*s++);
529 unsigned int byte = (digit1 << 4) | digit2;
530 *b++ = byte;
531 }
532 if(lenp) *lenp = blen;
533 return bytes;
534 }
535
536 int
getpadding(int offset,int alignment)537 getpadding(int offset, int alignment)
538 {
539 int rem = (alignment==0?0:(offset % alignment));
540 int pad = (rem==0?0:(alignment - rem));
541 return pad;
542 }
543
544 static void
reclaimSymbols(void)545 reclaimSymbols(void)
546 {
547 int i;
548 for(i=0;i<listlength(symlist);i++) {
549 Symbol* sym = listget(symlist,i);
550 freeSymbol(sym);
551 }
552 }
553
554 void
cleanup()555 cleanup()
556 {
557 reclaimSymbols();
558 }
559
560 /* compute the total n-dimensional size as 1 long array;
561 if stop == 0, then stop = dimset->ndims.
562 */
563 size_t
crossproduct(Dimset * dimset,int start,int stop)564 crossproduct(Dimset* dimset, int start, int stop)
565 {
566 size_t totalsize = 1;
567 int i;
568 for(i=start;i<stop;i++) {
569 totalsize = totalsize * dimset->dimsyms[i]->dim.declsize;
570 }
571 return totalsize;
572 }
573
574 /* Do the "complement" of crossproduct;
575 compute the total n-dimensional size of an array
576 starting at 0 thru the 'last' array index.
577 stop if we encounter an unlimited dimension
578 */
579 size_t
prefixarraylength(Dimset * dimset,int last)580 prefixarraylength(Dimset* dimset, int last)
581 {
582 return crossproduct(dimset,0,last+1);
583 }
584
585
586
587 #ifdef USE_HDF5
588 extern int H5Eprint1(FILE * stream);
589 #endif
590
591 void
check_err(const int stat,const int line,const char * file)592 check_err(const int stat, const int line, const char* file)
593 {
594 check_err2(stat,-1,line,file);
595 }
596
check_err2(const int stat,const int cdlline,const int line,const char * file)597 void check_err2(const int stat, const int cdlline, const int line, const char* file) {
598 if (stat != NC_NOERR) {
599 if(cdlline >= 0)
600 fprintf(stderr, "ncgen: cdl line %d; %s\n", cdlline, nc_strerror(stat));
601 else
602 fprintf(stderr, "ncgen: %s\n", nc_strerror(stat));
603 fprintf(stderr, "\t(%s:%d)\n", file,line);
604 #ifdef USE_HDF5
605 H5Eprint1(stderr);
606 #endif
607 fflush(stderr);
608 finalize_netcdf(1);
609 }
610 }
611
612 /**
613 Find the index of the first unlimited
614 dimension at or after 'start'.
615 If no unlimited exists, return |dimset|
616 */
617 int
findunlimited(Dimset * dimset,int start)618 findunlimited(Dimset* dimset, int start)
619 {
620 for(;start<dimset->ndims;start++) {
621 if(dimset->dimsyms[start]->dim.isunlimited)
622 return start;
623 }
624 return dimset->ndims;
625 }
626
627 /**
628 Find the index of the last unlimited
629 dimension.
630 If no unlimited exists, return |dimset|
631 */
632 int
findlastunlimited(Dimset * dimset)633 findlastunlimited(Dimset* dimset)
634 {
635 int i;
636 for(i=dimset->ndims-1;i>=0;i--) {
637 if(dimset->dimsyms[i]->dim.isunlimited)
638 return i;
639 }
640 return dimset->ndims;
641 }
642
643 /**
644 Count the number of unlimited dimensions.
645 */
646 int
countunlimited(Dimset * dimset)647 countunlimited(Dimset* dimset)
648 {
649 int i, count;
650 for(count=0,i=dimset->ndims-1;i>=0;i--) {
651 if(dimset->dimsyms[i]->dim.isunlimited)
652 count++;
653 }
654 return count;
655 }
656
657 /* Return standard format string */
658 const char *
kind_string(int kind)659 kind_string(int kind)
660 {
661 switch (kind) {
662 case 1: return "classic";
663 case 2: return "64-bit offset";
664 case 3: return "netCDF-4";
665 case 4: return "netCDF-4 classic model";
666 default:
667 derror("Unknown format index: %d\n",kind);
668 }
669 return NULL;
670 }
671