source: XIOS/dev/dev_cmip6_omp/extern/src_netcdf4/var.c @ 1606

Last change on this file since 1606 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 13.4 KB
Line 
1/*
2 *      Copyright 1996, University Corporation for Atmospheric Research
3 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5/* $Id: var.c,v 1.144 2010/05/30 00:50:35 russ Exp $ */
6
7#include "nc.h"
8#include <stdlib.h>
9#include <string.h>
10#include <assert.h>
11#include <limits.h>
12#include "ncx.h"
13#include "rnd.h"
14#include "utf8proc.h"
15
16#ifndef OFF_T_MAX
17#define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
18#endif
19
20/*
21 * Free var
22 * Formerly
23NC_free_var(var)
24 */
25void
26free_NC_var(NC_var *varp)
27{
28        if(varp == NULL)
29                return;
30        free_NC_attrarrayV(&varp->attrs);
31        free_NC_string(varp->name);
32#ifndef MALLOCHACK
33        if(varp->dimids != NULL) free(varp->dimids);
34        if(varp->shape != NULL) free(varp->shape);
35        if(varp->dsizes != NULL) free(varp->dsizes);
36#endif /*!MALLOCHACK*/
37        free(varp);
38}
39
40
41/*
42 * Common code for new_NC_var()
43 * and ncx_get_NC_var()
44 */
45NC_var *
46new_x_NC_var(
47        NC_string *strp,
48        size_t ndims)
49{
50        NC_var *varp;
51        const size_t o1 = M_RNDUP(ndims * sizeof(int));
52        const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
53
54#ifdef MALLOCHACK
55        const size_t sz =  M_RNDUP(sizeof(NC_var)) +
56                 o1 + o2 + ndims * sizeof(off_t);
57#else /*!MALLOCHACK*/
58        const size_t o3 = ndims * sizeof(off_t);
59        const size_t sz = sizeof(NC_var);
60#endif /*!MALLOCHACK*/
61
62        varp = (NC_var *) malloc(sz);
63        if(varp == NULL )
64                return NULL;
65        (void) memset(varp, 0, sz);
66        varp->name = strp;
67        varp->ndims = ndims;
68        varp->hash = hash_fast(strp->cp, strlen(strp->cp));
69
70        if(ndims != 0)
71        {
72#ifdef MALLOCHACK
73                /*
74                 * NOTE: lint may complain about the next 3 lines:
75                 * "pointer cast may result in improper alignment".
76                 * We use the M_RNDUP() macro to get the proper alignment.
77                 */
78                varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
79                varp->shape = (size_t *)((char *)varp->dimids + o1);
80                varp->dsizes = (off_t *)((char *)varp->shape + o2);
81#else /*!MALLOCHACK*/
82                varp->dimids = (int*)malloc(o1);
83                varp->shape = (size_t*)malloc(o2);
84                varp->dsizes = (off_t*)malloc(o3);
85#endif /*!MALLOCHACK*/
86        }
87
88        varp->xsz = 0;
89        varp->len = 0;
90        varp->begin = 0;
91
92        return varp;
93}
94
95
96/*
97 * Formerly
98NC_new_var()
99 */
100static NC_var *
101new_NC_var(const char *uname, nc_type type,
102        size_t ndims, const int *dimids)
103{
104        NC_string *strp;
105        NC_var *varp;
106
107        char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
108        if(name == NULL)
109            return NULL;
110        strp = new_NC_string(strlen(name), name);
111        free(name);
112        if(strp == NULL)
113                return NULL;
114
115        varp = new_x_NC_var(strp, ndims);
116        if(varp == NULL )
117        {
118                free_NC_string(strp);
119                return NULL;
120        }
121       
122        varp->type = type;
123
124        if( ndims != 0 && dimids != NULL)
125                (void) memcpy(varp->dimids, dimids, ndims * sizeof(int));
126
127        return(varp);
128}
129
130
131static NC_var *
132dup_NC_var(const NC_var *rvarp)
133{
134        NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type,
135                 rvarp->ndims, rvarp->dimids);
136        if(varp == NULL)
137                return NULL;
138
139       
140        if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
141        {
142                free_NC_var(varp);
143                return NULL;
144        }
145
146        (void) memcpy(varp->shape, rvarp->shape,
147                         rvarp->ndims * sizeof(size_t));
148        (void) memcpy(varp->dsizes, rvarp->dsizes,
149                         rvarp->ndims * sizeof(size_t));
150        varp->xsz = rvarp->xsz;
151        varp->len = rvarp->len;
152        varp->begin = rvarp->begin;
153
154        return varp;
155}
156
157
158/* vararray */
159
160
161/*
162 * Free the stuff "in" (referred to by) an NC_vararray.
163 * Leaves the array itself allocated.
164 */
165void
166free_NC_vararrayV0(NC_vararray *ncap)
167{
168        assert(ncap != NULL);
169
170        if(ncap->nelems == 0)
171                return;
172
173        assert(ncap->value != NULL);
174
175        {
176                NC_var **vpp = ncap->value;
177                NC_var *const *const end = &vpp[ncap->nelems];
178                for( /*NADA*/; vpp < end; vpp++)
179                {
180                        free_NC_var(*vpp);
181                        *vpp = NULL;
182                }
183        }
184        ncap->nelems = 0;
185}
186
187
188/*
189 * Free NC_vararray values.
190 * formerly
191NC_free_array()
192 */
193void
194free_NC_vararrayV(NC_vararray *ncap)
195{
196        assert(ncap != NULL);
197       
198        if(ncap->nalloc == 0)
199                return;
200
201        assert(ncap->value != NULL);
202
203        free_NC_vararrayV0(ncap);
204
205        free(ncap->value);
206        ncap->value = NULL;
207        ncap->nalloc = 0;
208}
209
210
211int
212dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
213{
214        int status = NC_NOERR;
215
216        assert(ref != NULL);
217        assert(ncap != NULL);
218
219        if(ref->nelems != 0)
220        {
221                const size_t sz = ref->nelems * sizeof(NC_var *);
222                ncap->value = (NC_var **) malloc(sz);
223                if(ncap->value == NULL)
224                        return NC_ENOMEM;
225                (void) memset(ncap->value, 0, sz);
226                ncap->nalloc = ref->nelems;
227        }
228
229        ncap->nelems = 0;
230        {
231                NC_var **vpp = ncap->value;
232                const NC_var **drpp = (const NC_var **)ref->value;
233                NC_var *const *const end = &vpp[ref->nelems];
234                for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++)
235                {
236                        *vpp = dup_NC_var(*drpp);
237                        if(*vpp == NULL)
238                        {
239                                status = NC_ENOMEM;
240                                break;
241                        }
242                }
243        }
244
245        if(status != NC_NOERR)
246        {
247                free_NC_vararrayV(ncap);
248                return status;
249        }
250
251        assert(ncap->nelems == ref->nelems);
252
253        return NC_NOERR;
254}
255
256
257/*
258 * Add a new handle on the end of an array of handles
259 * Formerly
260NC_incr_array(array, tail)
261 */
262static int
263incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp)
264{
265        NC_var **vp;
266
267        assert(ncap != NULL);
268
269        if(ncap->nalloc == 0)
270        {
271                assert(ncap->nelems == 0);
272                vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
273                if(vp == NULL)
274                        return NC_ENOMEM;
275                ncap->value = vp;
276                ncap->nalloc = NC_ARRAY_GROWBY;
277        }
278        else if(ncap->nelems +1 > ncap->nalloc)
279        {
280                vp = (NC_var **) realloc(ncap->value,
281                        (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
282                if(vp == NULL)
283                        return NC_ENOMEM;
284                ncap->value = vp;
285                ncap->nalloc += NC_ARRAY_GROWBY;
286        }
287
288        if(newelemp != NULL)
289        {
290                ncap->value[ncap->nelems] = newelemp;
291                ncap->nelems++;
292        }
293        return NC_NOERR;
294}
295
296
297static NC_var *
298elem_NC_vararray(const NC_vararray *ncap, size_t elem)
299{
300        assert(ncap != NULL);
301                /* cast needed for braindead systems with signed size_t */
302        if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
303                return NULL;
304
305        assert(ncap->value != NULL);
306
307        return ncap->value[elem];
308}
309
310
311/* End vararray per se */
312
313
314/*
315 * Step thru NC_VARIABLE array, seeking match on name.
316 * Return varid or -1 on not found.
317 * *varpp is set to the appropriate NC_var.
318 * Formerly (sort of)
319NC_hvarid
320 */
321int
322NC_findvar(const NC_vararray *ncap, const char *uname, NC_var **varpp)
323{
324        NC_var **loc;
325        uint32_t shash;
326        int varid;
327        char *name;
328
329        assert(ncap != NULL);
330
331        if(ncap->nelems == 0)
332                return -1;
333
334        loc = (NC_var **) ncap->value;
335
336        /* normalized version of uname */
337        name = (char *)utf8proc_NFC((const unsigned char *)uname);
338        if(name == NULL)
339            return NC_ENOMEM;
340        shash = hash_fast(name, strlen(name));
341
342        for(varid = 0; (size_t) varid < ncap->nelems; varid++, loc++)
343        {
344                if((*loc)->hash == shash &&
345                   strncmp((*loc)->name->cp, name, strlen(name)) == 0)
346                {
347                        if(varpp != NULL)
348                                *varpp = *loc;
349                        free(name);
350                        return(varid); /* Normal return */
351                }
352        }
353        free(name);
354        return(-1); /* not found */
355}
356
357/*
358 * For a netcdf type
359 *  return the size of one element in the external representation.
360 * Note that arrays get rounded up to X_ALIGN boundaries.
361 * Formerly
362NC_xtypelen
363 * See also ncx_len()
364 */
365size_t
366ncx_szof(nc_type type)
367{
368        switch(type){
369        case NC_BYTE:
370        case NC_CHAR:
371                return(1);
372        case NC_SHORT :
373                return(2);
374        case NC_INT:
375                return X_SIZEOF_INT;
376        case NC_FLOAT:
377                return X_SIZEOF_FLOAT;
378        case NC_DOUBLE :
379                return X_SIZEOF_DOUBLE;
380        default:
381                assert("ncx_szof invalid type" == 0);
382                return 0;
383        }
384}
385
386
387/*
388 * 'compile' the shape and len of a variable
389 *  Formerly
390NC_var_shape(var, dims)
391 */
392int
393NC_var_shape(NC_var *varp, const NC_dimarray *dims)
394{
395        size_t *shp, *op;
396        off_t *dsp;
397        int *ip;
398        const NC_dim *dimp;
399        off_t product = 1;
400       
401        varp->xsz = ncx_szof(varp->type);
402
403        if(varp->ndims == 0)
404        {
405                goto out;
406        }
407
408        /*
409         * use the user supplied dimension indices
410         * to determine the shape
411         */
412        for(ip = varp->dimids, op = varp->shape
413                ; ip < &varp->dimids[varp->ndims]; ip++, op++)
414        {
415                if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
416                        return NC_EBADDIM;
417               
418                dimp = elem_NC_dimarray(dims, (size_t)*ip);
419                *op = dimp->size;
420                if(*op == NC_UNLIMITED && ip != varp->dimids)
421                        return NC_EUNLIMPOS;
422        }
423
424        /*
425         * Compute the dsizes
426         */
427                                /* ndims is > 0 here */
428        for(shp = varp->shape + varp->ndims -1,
429                                dsp = varp->dsizes + varp->ndims -1;
430                        shp >= varp->shape;
431                        shp--, dsp--)
432        {
433                if(!(shp == varp->shape && IS_RECVAR(varp)))
434                {
435                    if( (off_t)(*shp) <= OFF_T_MAX / product ) 
436                        {
437                                product *= *shp;
438                        } else 
439                        {
440                                product = OFF_T_MAX ;
441                        }
442                }
443                *dsp = product;
444        }
445
446
447out :
448    if( varp->xsz <= (X_UINT_MAX - 1) / product ) /* if integer multiply will not overflow */
449        {
450                varp->len = product * varp->xsz;
451                switch(varp->type) {
452                case NC_BYTE :
453                case NC_CHAR :
454                case NC_SHORT :
455                        if( varp->len%4 != 0 )
456                        {
457                                varp->len += 4 - varp->len%4; /* round up */
458                /*              *dsp += 4 - *dsp%4; */
459                    }
460                    break;
461                default:
462                        /* already aligned */
463                        break;
464                }
465        } else
466        {       /* OK for last var to be "too big", indicated by this special len */
467                varp->len = X_UINT_MAX;
468        }
469#if 0
470        arrayp("\tshape", varp->ndims, varp->shape);
471        arrayp("\tdsizes", varp->ndims, varp->dsizes);
472#endif
473        return NC_NOERR;
474}
475
476/*
477 * Check whether variable size is less than or equal to vlen_max,
478 * without overflowing in arithmetic calculations.  If OK, return 1,
479 * else, return 0.  For CDF1 format or for CDF2 format on non-LFS
480 * platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
481 * systems with LFS it should be 2^32 - 4.
482 */
483int
484NC_check_vlen(NC_var *varp, size_t vlen_max) {
485    size_t prod=varp->xsz;      /* product of xsz and dimensions so far */
486
487    int ii;
488
489    assert(varp != NULL);
490    for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndims; ii++) {
491        if (varp->shape[ii] > vlen_max / prod) {
492            return 0;           /* size in bytes won't fit in a 32-bit int */
493        }
494        prod *= varp->shape[ii];
495    }
496    return 1;                   /* OK */
497}
498
499
500/*
501 * Given valid ncp and varid, return var
502 *  else NULL on error
503 * Formerly
504NC_hlookupvar()
505 */
506NC_var *
507NC_lookupvar(NC *ncp, int varid)
508{
509        NC_var *varp;
510
511        if(varid == NC_GLOBAL)
512        {
513                /* Global is error in this context */
514                return(NULL);
515        }
516
517        varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
518        if(varp == NULL)
519        {
520                return NULL;
521        }
522
523        assert(varp != NULL);
524
525        return(varp);
526}
527
528
529/* Public */
530
531int
532NC3_def_var( int ncid, const char *name, nc_type type,
533         int ndims, const int *dimids, int *varidp)
534{
535        int status;
536        NC *ncp;
537        int varid;
538        NC_var *varp;
539
540        status = NC_check_id(ncid, &ncp); 
541        if(status != NC_NOERR)
542                return status;
543
544        if(!NC_indef(ncp))
545        {
546                return NC_ENOTINDEFINE;
547        }
548
549        status = NC_check_name(name);
550        if(status != NC_NOERR)
551                return status;
552
553        status = nc_cktype(type);
554        if(status != NC_NOERR)
555                return status;
556
557                /* cast needed for braindead systems with signed size_t */
558        if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
559        {
560                return NC_EINVAL;
561        } 
562
563        if(ncp->vars.nelems >= NC_MAX_VARS)
564        {
565                return NC_EMAXVARS;
566        }
567
568        varid = NC_findvar(&ncp->vars, name, &varp);
569        if(varid != -1)
570        {
571                return NC_ENAMEINUSE;
572        }
573       
574        varp = new_NC_var(name, type, ndims, dimids);
575        if(varp == NULL)
576                return NC_ENOMEM;
577
578        status = NC_var_shape(varp, &ncp->dims);
579        if(status != NC_NOERR)
580        {
581                free_NC_var(varp);
582                return status;
583        }
584
585        status = incr_NC_vararray(&ncp->vars, varp);
586        if(status != NC_NOERR)
587        {
588                free_NC_var(varp);
589                return status;
590        }
591
592        if(varidp != NULL)
593                *varidp = (int)ncp->vars.nelems -1; /* varid */
594        return NC_NOERR;
595}
596
597
598int
599NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
600{
601        int status;
602        NC *ncp;
603        NC_var *varp;
604        int varid;
605
606        status = NC_check_id(ncid, &ncp); 
607        if(status != NC_NOERR)
608                return status;
609
610        varid = NC_findvar(&ncp->vars, name, &varp);
611        if(varid == -1)
612        {
613                return NC_ENOTVAR;
614        }
615
616        *varid_ptr = varid;
617        return NC_NOERR;
618}
619
620
621int
622NC3_inq_var(int ncid,
623        int varid,
624        char *name,
625        nc_type *typep,
626        int *ndimsp,
627        int *dimids,
628        int *nattsp)
629{
630        int status;
631        NC *ncp;
632        NC_var *varp;
633        size_t ii;
634
635        status = NC_check_id(ncid, &ncp); 
636        if(status != NC_NOERR)
637                return status;
638
639        varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
640        if(varp == NULL)
641                return NC_ENOTVAR;
642
643        if(name != NULL)
644        {
645                (void) strncpy(name, varp->name->cp, varp->name->nchars);
646                name[varp->name->nchars] = 0;
647        }
648
649        if(typep != 0)
650                *typep = varp->type;
651        if(ndimsp != 0)
652        {
653                *ndimsp = (int) varp->ndims;
654        }
655        if(dimids != 0)
656        {
657                for(ii = 0; ii < varp->ndims; ii++)
658                {
659                        dimids[ii] = varp->dimids[ii];
660                }
661        }
662        if(nattsp != 0)
663        {
664                *nattsp = (int) varp->attrs.nelems;
665        }
666
667        return NC_NOERR;
668}
669
670int
671NC3_rename_var(int ncid, int varid, const char *unewname)
672{
673        int status;
674        NC *ncp;
675        NC_var *varp;
676        NC_string *old, *newStr;
677        int other;
678        char *newname;          /* normalized */
679
680        status = NC_check_id(ncid, &ncp); 
681        if(status != NC_NOERR)
682                return status;
683
684        if(NC_readonly(ncp))
685        {
686                return NC_EPERM;
687        }
688
689        status = NC_check_name(unewname);
690        if(status != NC_NOERR)
691                return status;
692
693        /* check for name in use */
694        other = NC_findvar(&ncp->vars, unewname, &varp);
695        if(other != -1)
696        {
697                return NC_ENAMEINUSE;
698        }
699       
700        varp = NC_lookupvar(ncp, varid);
701        if(varp == NULL)
702        {
703                /* invalid varid */
704                return NC_ENOTVAR; /* TODO: is this the right error code? */
705        }
706
707        old = varp->name;
708        newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
709        if(newname == NULL)
710            return NC_ENOMEM;
711        if(NC_indef(ncp))
712        {
713                newStr = new_NC_string(strlen(newname),newname);
714                free(newname);
715                if(newStr == NULL)
716                        return(-1);
717                varp->name = newStr;
718                varp->hash = hash_fast(newStr->cp, strlen(newStr->cp));
719                free_NC_string(old);
720                return NC_NOERR;
721        }
722
723        /* else, not in define mode */
724        status = set_NC_string(varp->name, newname);
725        varp->hash = hash_fast(newname, strlen(newname));
726        free(newname);
727        if(status != NC_NOERR)
728                return status;
729
730        set_NC_hdirty(ncp);
731
732        if(NC_doHsync(ncp))
733        {
734                status = NC_sync(ncp);
735                if(status != NC_NOERR)
736                        return status;
737        }
738
739        return NC_NOERR;
740}
Note: See TracBrowser for help on using the repository browser.