1/*********************************************************************
2 *   Copyright 1993, 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) */
10Symbolprimsymbols[PRIMNO];
11
12char*
13append(const char* s1, const char* s2)
14{
15    int len = (s1?strlen(s1):0)+(s2?strlen(s2):0);
16    char* result = (char*)emalloc(len+1);
17    result[0] = '\0';
18    if(s1) strcat(result,s1);
19    if(s2) strcat(result,s2);
20    return result;
21}
22
23
24unsigned int
25chartohex(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 */
45void
46expe2d(
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 */
56int
57pow2(
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 */
76void
77tztrim(
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/* Assume bytebuffer contains pointers to char**/
103void
104reclaimattptrs(void* buf, long count)
105{
106    int i;
107    char** ptrs = (char**)buf;
108    for(i=0;i<count;i++) {free((void*)ptrs[i]);}
109}
110
111void
112freeSymbol(Symbolsym)
113{
114#ifdef FIX
115    switch (sym->objectclass) {
116    case NG_VAR:
117 reclaimconstlist(vsym->var.data);
118 if(vsym->var.dims != NULLefree(vsym->var.dims);
119 break;
120    case NG_ATT:
121 if(asym->att.basetype == primsymbols[NC_STRING])
122       reclaimattptrs(asym->att.data,asym->att.count);
123 else
124     efree(asym->att.data);
125 break;
126    case NG_GRP:
127    case NG_DIM:
128    case NG_TYP:
129    case NG_ENUM:
130    case NG_ECONST:
131    case NG_VLEN:
132    case NG_STRUCT:
133    case NG_FIELD:
134    case NG_OPAQUE:
135    default: break;
136    }
137    efree(sym->name);
138    efree(sym);
139#endif
140}
141
142char* nctypenames[17] = {
143"NC_NAT",
144"NC_BYTE", "NC_CHAR", "NC_SHORT", "NC_INT",
145"NC_FLOAT", "NC_DOUBLE",
146"NC_UBYTE", "NC_USHORT", "NC_UINT",
147"NC_INT64", "NC_UINT64",
148"NC_STRING",
149"NC_VLEN", "NC_OPAQUE", "NC_ENUM", "NC_COMPOUND"
150};
151
152char* nctypenamesextend[9] = {
153"NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT", "NC_TYPE",
154"NC_ECONST","NC_FIELD", "NC_ARRAY","NC_PRIM"
155};
156
157char*
158nctypename(nc_type nctype)
159{
160    char* s;
161    if(nctype >= NC_NAT && nctype <= NC_COMPOUND)
162 return nctypenames[nctype];
163    if(nctype >= NC_GRP && nctype <= NC_PRIM)
164 return nctypenamesextend[(nctype - NC_GRP)];
165    if(nctype == NC_FILLVALUE) return "NC_FILL";
166    if(nctype == NC_NIL) return "NC_NIL";
167    s = poolalloc(128);
168    sprintf(s,"NC_<%d>",nctype);
169    return s;
170}
171
172/* These are the augmented NC_ values (0 based from NC_GRP)*/
173char* ncclassnames[9] = {
174"NC_GRP", "NC_DIM", "NC_VAR", "NC_ATT",
175"NC_TYP", "NC_ECONST", "NC_FIELD", "NC_ARRAY",
176"NC_PRIM"
177};
178
179char*
180ncclassname(nc_class ncc)
181{
182    char* s;
183    if(ncc >= NC_NAT && ncc <= NC_COMPOUND)
184 return nctypename((nc_type)ncc);
185    if(ncc == NC_FILLVALUE) return "NC_FILL";
186    if(ncc >= NC_GRP && ncc <= NC_PRIM)
187 return ncclassnames[ncc - NC_GRP];
188    s = poolalloc(128);
189    sprintf(s,"NC_<%d>",ncc);
190    return s;
191}
192
193int ncsizes[17] = {
1940,
1951,1,2,4,
1964,8,
1971,2,4,
1988,8,
199sizeof(char*),
200sizeof(nc_vlen_t),
2010,0,0
202};
203
204int
205ncsize(nc_type nctype)
206{
207    if(nctype >= NC_NAT && nctype <= NC_COMPOUND)
208 return ncsizes[nctype];
209    return 0;
210}
211
212int
213hasunlimited(Dimsetdimset)
214{
215    int i;
216    for(i=0;i<dimset->ndims;i++) {
217 Symboldim = dimset->dimsyms[i];
218 if(dim->dim.declsize == NC_UNLIMITED) return 1;
219    }
220    return 0;
221}
222
223/* return 1 if first dimension is unlimited*/
224int
225isunlimited0(Dimsetdimset)
226{
227   return (dimset->ndims > 0 && dimset->dimsyms[0]->dim.declsize == NC_UNLIMITED);
228}
229
230
231/* True only if dim[0] is unlimited all rest are bounded*/
232/* or all are bounded*/
233int
234classicunlimited(Dimsetdimset)
235{
236    int i;
237    int last = -1;
238    for(i=0;i<dimset->ndims;i++) {
239 Symboldim = dimset->dimsyms[i];
240 if(dim->dim.declsize == NC_UNLIMITEDlast = i;
241    }
242    return (last < 1);
243}
244
245/* True only iff no dimension is unlimited*/
246int
247isbounded(Dimsetdimset)
248{
249    int i;
250    for(i=0;i<dimset->ndims;i++) {
251 Symboldim = dimset->dimsyms[i];
252 if(dim->dim.declsize == NC_UNLIMITED) return 0;
253    }
254    return 1;
255}
256
257int
258signedtype(nc_type nctype)
259{
260    switch (nctype) {
261    case NC_BYTE:
262    case NC_SHORT:
263    case NC_INT:
264    case NC_INT64:
265 return nctype;
266    case NC_UBYTE: return NC_BYTE;
267    case NC_USHORT: return NC_SHORT;
268    case NC_UINT: return NC_INT;
269    case NC_UINT64: return NC_INT64;
270    default: break;
271    }
272    return nctype;
273}
274
275int
276unsignedtype(nc_type nctype)
277{
278    switch (nctype) {
279    case NC_UBYTE:
280    case NC_USHORT:
281    case NC_UINT:
282    case NC_UINT64:
283 return nctype;
284    case NC_BYTE: return NC_UBYTE;
285    case NC_SHORT: return NC_USHORT;
286    case NC_INT: return NC_UINT;
287    case NC_INT64: return NC_UINT64;
288    default: break;
289    }
290    return nctype;
291}
292
293int
294isinttype(nc_type nctype)
295{
296    return (nctype != NC_CHAR)
297            && ((nctype >= NC_BYTE && nctype <= NC_INT)
298         || (nctype >= NC_UBYTE && nctype <= NC_UINT64));
299}
300
301int
302isuinttype(nc_type t)
303{
304    return isinttype(t)
305    && t >= NC_UBYTE
306           && t <= NC_UINT64
307           && t != NC_INT64;
308}
309
310int
311isfloattype(nc_type nctype)
312{
313    return (nctype == NC_FLOAT || nctype <= NC_DOUBLE);
314}
315
316int
317isclassicprim(nc_type nctype)
318{
319    return    (nctype >= NC_BYTE && nctype <= NC_DOUBLE)
320 ;
321}
322
323int
324isclassicprimplus(nc_type nctype)
325{
326    return    (nctype >= NC_BYTE && nctype <= NC_DOUBLE)
327    || (nctype == NC_STRING)
328 ;
329}
330
331int
332isprim(nc_type nctype)
333{
334    return    (nctype >= NC_BYTE && nctype <= NC_STRING)
335 ;
336}
337
338int
339isprimplus(nc_type nctype)
340{
341    return    (nctype >= NC_BYTE && nctype <= NC_STRING)
342    || (nctype == NC_ECONST)
343    || (nctype == NC_OPAQUE)
344  ;
345}
346
347void
348collectpath(SymbolgrpListgrpstack)
349{
350    while(grp != NULL) {
351        listpush(grpstack,(void*)grp);
352 grp = grp->container;
353    }
354}
355
356
357#ifdef USE_NETCDF4
358/* Result is pool'd*/
359char*
360prefixtostring(Listprefix, char* separator)
361{
362    int slen=0;
363    int plen;
364    int i;
365    char* result;
366    if(prefix == NULL) return pooldup("");
367    plen = prefixlen(prefix);
368    if(plen == 0) { /* root prefix*/
369 slen=0;
370        /* slen += strlen(separator);*/
371        slen++; /* for null terminator*/
372        result = poolalloc(slen);
373        result[0] = '\0';
374 /*strcat(result,separator);*/
375    } else {
376        for(i=0;i<plen;i++) {
377     Symbolsym = (Symbol*)listget(prefix,i);
378            slen += (strlen(separator)+strlen(sym->name));
379 }
380        slen++; /* for null terminator*/
381        result = poolalloc(slen);
382        result[0] = '\0';
383        for(i=0;i<plen;i++) {
384     Symbolsym = (Symbol*)listget(prefix,i);
385            strcat(result,separator);
386     strcat(result,sym->name); /* append "/<prefix[i]>"*/
387 }
388    }
389    return result;
390}
391#endif
392
393/* Result is pool'd*/
394char*
395fullname(Symbolsym)
396{
397#ifdef USE_NETCDF4
398    char* s1;
399    char* result;
400    char* prefix;
401    prefix = prefixtostring(sym->prefix,PATHSEPARATOR);
402    s1 = poolcat(prefix,PATHSEPARATOR);
403    result = poolcat(s1,sym->name);
404    return result;
405#else
406    return nulldup(sym->name);
407#endif
408}
409
410int
411prefixeq(Listx1Listx2)
412{
413    Symbol** l1;
414    Symbol** l2;
415    int len,i;
416    if((len=listlength(x1)) != listlength(x2)) return 0;
417    l1=(Symbol**)listcontents(x1);
418    l2=(Symbol**)listcontents(x2);
419    for(i=0;i<len;i++) {
420        if(strcmp(l1[i]->name,l2[i]->name) != 0) return 0;
421    }
422    return 1;
423}
424
425List*
426prefixdup(Listprefix)
427{
428    Listdupseq;
429    int i;
430    if(prefix == NULL) return listnew();
431    dupseq = listnew();
432    listsetalloc(dupseq,listlength(prefix));
433    for(i=0;i<listlength(prefix);i++) listpush(dupseq,listget(prefix,i));
434    return dupseq;
435}
436
437/*
438Many of the generate routines need to construct
439heap strings for short periods. Remembering to
440free such space is error prone, so provide a
441pseudo-GC to handle these short term requests.
442The idea is to have a fixed size pool
443tracking malloc requests and automatically
444releasing when the pool gets full.
445*/
446
447/* Max number of allocated pool items*/
448#define POOLMAX 100
449
450static char* pool[POOLMAX];
451static int poolindex = -1;
452#define POOL_DEFAULT 256
453
454char*
455poolalloc(size_t length)
456{
457    if(poolindex == -1) { /* initialize*/
458 memset((void*)pool,0,sizeof(pool));
459 poolindex = 0;
460    }
461    if(poolindex == POOLMAXpoolindex=0;
462    if(length == 0) length = POOL_DEFAULT;
463    if(pool[poolindex] != NULLefree(pool[poolindex]);
464    pool[poolindex] = (char*)emalloc(length);
465    return pool[poolindex++];
466}
467
468char*
469pooldup(const char* s)
470{
471    char* sdup = poolalloc(strlen(s)+1);
472    strncpy(sdup,s,(strlen(s)+1));
473    return sdup;
474}
475
476char*
477poolcat(const char* s1, const char* s2)
478{
479    int len1len2;
480    char* cat;
481    if(s1 == NULL && s2 == NULL) return NULL;
482    len1 = (s1?strlen(s1):0);
483    len2 = (s2?strlen(s2):0);
484    cat = poolalloc(len1+len2+1);
485    cat[0] = '\0';
486    if(s1 != NULL) strcat(cat,s1);
487    if(s2 != NULL) strcat(cat,s2);
488    return cat;
489}
490
491/* Result is malloc'd*/
492unsigned char*
493makebytestring(char* s, size_t* lenp)
494{
495    unsigned char* bytes;
496    unsigned char* b;
497    size_t slen = strlen(s); /* # nibbles */
498    size_t blen = slen/2; /* # bytes */
499    int i;
500
501    ASSERT((slen%2) == 0);
502    ASSERT(blen > 0);
503    bytes = (unsigned char*)emalloc(blen);
504    b = bytes;
505    for(i=0;i<slen;i+=2) {
506 unsigned int digit1 = chartohex(*s++);
507 unsigned int digit2 = chartohex(*s++);
508 unsigned int byte = (digit1 << 4) | digit2;
509 *b++ = byte;
510    }
511    if(lenp) *lenp = blen;
512    return bytes;
513}
514
515int
516getpadding(int offset, int alignment)
517{
518    int rem = (alignment==0?0:(offset % alignment));
519    int pad = (rem==0?0:(alignment - rem));
520    return pad;
521}
522
523static void
524reclaimSymbols(void)
525{
526    Symbolsym;
527    for(sym=symlist;sym;) {
528 Symbolnext = sym->next;
529        freeSymbol(sym);
530 sym = next;
531    }
532}
533
534static void
535constantFree(NCConstantcon)
536{
537    switch(con->nctype) {
538    case NC_COMPOUND:
539 /* do nothing; ReclaimDatalists below will take care of the datalist */
540 break;
541    case NC_STRING:
542 if(con->value.stringv.len > 0 && con->value.stringv.stringv != NULL)
543     efree(con->value.stringv.stringv);
544 break;
545    case NC_OPAQUE:
546 if(con->value.opaquev.len > 0 && con->value.opaquev.stringv != NULL)
547     efree(con->value.opaquev.stringv);
548 break;
549    default:
550 break;
551    }
552}
553
554static void
555reclaimDatalists(void)
556{
557    Datalistlist;
558    NCConstantcon;
559    /* Step 1: free up the constant content of each datalist*/
560    for(list=alldatalists;list != NULLlist = list->next) {
561 if(list->data != NULL) { /* avoid multiple free attempts*/
562     int i;
563     for(i=0,con=list->data;i<list->length;i++,con++)
564         constantFree(con);
565     list->data = NULL;
566 }
567    }
568    /* Step 2: free up the datalist itself*/
569    for(list=alldatalists;list != NULL;) {
570 Datalistcurrent = list;
571 list = list->next;
572 efree(current);
573    }
574}
575
576void
577cleanup()
578{
579  reclaimDatalists();
580  reclaimSymbols();
581}
582
583
584
585
586
587/* compute the total n-dimensional size as 1 long array;
588   if stop == 0, then stop = dimset->ndims.
589*/
590size_t
591crossproduct(Dimsetdimset, int start, int stop)
592{
593    size_t totalsize = 1;
594    int i;
595    for(i=start;i<stop;i++) {
596 totalsize = totalsize * dimset->dimsyms[i]->dim.declsize;
597    }
598    return totalsize;
599}
600
601/* Do the "complement" of crossproduct;
602   compute the total n-dimensional size of an array
603   starting at 0 thru the 'last' array index.
604   stop if we encounter an unlimited dimension
605*/
606size_t
607prefixarraylength(Dimsetdimset, int last)
608{
609    return crossproduct(dimset,0,last+1);
610}
611
612
613
614#ifdef USE_NETCDF4
615extern int H5Eprint1(FILE * stream);
616#endif
617
618void
619check_err(const int stat, const int line, const char* file)
620{
621    check_err2(stat,-1,line,file);
622}
623
624void check_err2(const int stat, const int cdlline, const int line, const char* file) {
625    if (stat != NC_NOERR) {
626 if(cdlline >= 0)
627     fprintf(stderr, "ncgen: cdl line %d; %s\n", cdllinenc_strerror(stat));
628 else
629     fprintf(stderr, "ncgen: %s\n", nc_strerror(stat));
630 fprintf(stderr, "\t(%s:%d)\n", file,line);
631#ifdef USE_NETCDF4
632 H5Eprint1(stderr);
633#endif
634 fflush(stderr);
635 exit(1);
636    }
637}
638
639/**
640Find the index of the first unlimited
641dimension at or after 'start'.
642If no unlimited exists, return |dimset|
643*/
644int
645findunlimited(Dimsetdimset, int start)
646{
647    for(;start<dimset->ndims;start++) {
648 if(dimset->dimsyms[start]->dim.isunlimited)
649     return start;
650    }
651    return dimset->ndims;
652}
653
654/**
655Find the index of the last unlimited
656dimension.
657If no unlimited exists, return |dimset|
658*/
659int
660findlastunlimited(Dimsetdimset)
661{
662    int i;
663    for(i=dimset->ndims-1;i>=0;i--) {
664 if(dimset->dimsyms[i]->dim.isunlimited)
665     return i;
666    }
667    return dimset->ndims;
668}
669
670/**
671Count the number of unlimited dimensions.
672*/
673int
674countunlimited(Dimsetdimset)
675{
676    int icount;
677    for(count=0,i=dimset->ndims-1;i>=0;i--) {
678 if(dimset->dimsyms[i]->dim.isunlimited)
679     count++;
680    }
681    return count;
682}
683
684/* Return standard format string */
685const char *
686kind_string(int kind)
687{
688    switch (kind) {
689    case 1: return "classic";
690    case 2: return "64-bit offset";
691    case 3: return "netCDF-4";
692    case 4: return "netCDF-4 classic model";
693    default:
694 derror("Unknown format index: %d\n",kind);
695    }
696    return NULL;
697}
698
699#ifdef USE_NETCDF4i
700nt
701getrootid(int grpid)
702{
703    int current = grpid;
704    int parent = current;
705    /* see if root id */
706    for(;;) {
707        int stat = nc_inq_grp_parent(current,&parent);
708        if(stat) break;
709 current = parent;
710    }
711    return current;
712}
713#endif


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed