Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libsrc/var.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright 2018, 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
#if HAVE_CONFIG_H
8
#include <config.h>
9
#endif
10
11
#include "nc3internal.h"
12
#include <stdlib.h>
13
#include <string.h>
14
#include <assert.h>
15
#include <limits.h>
16
#include "ncx.h"
17
#include "rnd.h"
18
#include "ncutf8.h"
19
#include "nc3dispatch.h"
20
21
#ifndef OFF_T_MAX
22
#if 0
23
#define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
24
#endif
25
26
/* The behavior above is undefined, re: bitshifting a negative value, according
27
   to warnings thrown by clang/gcc.  An alternative OFF_T_MAX was written
28
   based on info found at:
29
   * http://stackoverflow.com/questions/4514572/c-question-off-t-and-other-signed-integer-types-minimum-and-maximum-values
30
   */
31
#define MAX_INT_VAL_STEP(t) \
32
0
    ((t) 1 << (CHAR_BIT * sizeof(t) - 1 - ((t) -1 < 1)))
33
34
#define MAX_INT_VAL(t) \
35
0
    ((MAX_INT_VAL_STEP(t) - 1) + MAX_INT_VAL_STEP(t))
36
37
#define MIN_INT_VAL(t) \
38
    ((t) -MAX_INT_VAL(t) - 1)
39
40
0
#define OFF_T_MAX MAX_INT_VAL(off_t)
41
42
#endif
43
44
/*
45
 * Free var
46
 * Formerly NC_free_var(var)
47
 */
48
void
49
free_NC_var(NC_var *varp)
50
48.4k
{
51
48.4k
  if(varp == NULL)
52
0
    return;
53
48.4k
  free_NC_attrarrayV(&varp->attrs);
54
48.4k
  free_NC_string(varp->name);
55
48.4k
#ifndef MALLOCHACK
56
48.4k
  if(varp->dimids != NULL) free(varp->dimids);
57
48.4k
  if(varp->shape != NULL) free(varp->shape);
58
48.4k
  if(varp->dsizes != NULL) free(varp->dsizes);
59
48.4k
#endif /*!MALLOCHACK*/
60
48.4k
  free(varp);
61
48.4k
}
62
63
64
/*
65
 * Common code for new_NC_var()
66
 * and ncx_get_NC_var()
67
 */
68
NC_var *
69
new_x_NC_var(
70
  NC_string *strp,
71
  size_t ndims)
72
48.4k
{
73
48.4k
  NC_var *varp;
74
48.4k
  const size_t o1 = M_RNDUP(ndims * sizeof(int));
75
48.4k
  const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
76
77
#ifdef MALLOCHACK
78
  const size_t sz =  M_RNDUP(sizeof(NC_var)) +
79
     o1 + o2 + ndims * sizeof(off_t);
80
#else /*!MALLOCHACK*/
81
48.4k
  const size_t o3 = ndims * sizeof(off_t);
82
48.4k
  const size_t sz = sizeof(NC_var);
83
48.4k
#endif /*!MALLOCHACK*/
84
85
48.4k
  varp = (NC_var *) malloc(sz);
86
48.4k
  if(varp == NULL )
87
0
    return NULL;
88
48.4k
  (void) memset(varp, 0, sz);
89
48.4k
  varp->name = strp;
90
48.4k
  varp->ndims = ndims;
91
92
48.4k
  if(ndims != 0)
93
7.06k
  {
94
#ifdef MALLOCHACK
95
    /*
96
     * NOTE: lint may complain about the next 3 lines:
97
     * "pointer cast may result in improper alignment".
98
     * We use the M_RNDUP() macro to get the proper alignment.
99
     */
100
    varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
101
    varp->shape = (size_t *)((char *)varp->dimids + o1);
102
    varp->dsizes = (off_t *)((char *)varp->shape + o2);
103
#else /*!MALLOCHACK*/
104
7.06k
    varp->dimids = (int*)malloc(o1);
105
7.06k
    varp->shape = (size_t*)malloc(o2);
106
7.06k
    varp->dsizes = (off_t*)malloc(o3);
107
7.06k
#endif /*!MALLOCHACK*/
108
41.3k
  } else {
109
41.3k
    varp->dimids = NULL;
110
41.3k
    varp->shape = NULL;
111
41.3k
    varp->dsizes=NULL;
112
41.3k
  }
113
114
115
48.4k
  varp->xsz = 0;
116
48.4k
  varp->len = 0;
117
48.4k
  varp->begin = 0;
118
119
48.4k
  return varp;
120
48.4k
}
121
122
123
/*
124
 * Formerly
125
NC_new_var()
126
 */
127
static NC_var *
128
new_NC_var(const char *uname, nc_type type,
129
  size_t ndims, const int *dimids)
130
0
{
131
0
  NC_string *strp = NULL;
132
0
  NC_var *varp = NULL;
133
0
  int stat;
134
0
  char* name;
135
136
0
        stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name);
137
0
        if(stat != NC_NOERR)
138
0
      return NULL;
139
0
  strp = new_NC_string(strlen(name), name);
140
0
  free(name);
141
0
  if(strp == NULL)
142
0
    return NULL;
143
144
0
  varp = new_x_NC_var(strp, ndims);
145
0
  if(varp == NULL )
146
0
  {
147
0
    free_NC_string(strp);
148
0
    return NULL;
149
0
  }
150
151
0
  varp->type = type;
152
153
0
  if( ndims != 0 && dimids != NULL)
154
0
    (void) memcpy(varp->dimids, dimids, ndims * sizeof(int));
155
0
    else
156
0
      varp->dimids=NULL;
157
158
159
0
  return(varp);
160
0
}
161
162
163
static NC_var *
164
dup_NC_var(const NC_var *rvarp)
165
0
{
166
0
  NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type,
167
0
     rvarp->ndims, rvarp->dimids);
168
0
  if(varp == NULL)
169
0
    return NULL;
170
171
172
0
  if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
173
0
  {
174
0
    free_NC_var(varp);
175
0
    return NULL;
176
0
  }
177
178
0
  if(rvarp->shape != NULL)
179
0
    (void) memcpy(varp->shape, rvarp->shape,
180
0
         rvarp->ndims * sizeof(size_t));
181
0
  if(rvarp->dsizes != NULL)
182
0
    (void) memcpy(varp->dsizes, rvarp->dsizes,
183
0
         rvarp->ndims * sizeof(off_t));
184
0
  varp->xsz = rvarp->xsz;
185
0
  varp->len = rvarp->len;
186
0
  varp->begin = rvarp->begin;
187
188
0
  return varp;
189
0
}
190
191
192
/* vararray */
193
194
195
/*
196
 * Free the stuff "in" (referred to by) an NC_vararray.
197
 * Leaves the array itself allocated.
198
 */
199
void
200
free_NC_vararrayV0(NC_vararray *ncap)
201
30
{
202
30
  assert(ncap != NULL);
203
204
30
  if(ncap->nelems == 0)
205
1
    return;
206
207
29
  assert(ncap->value != NULL);
208
209
29
  {
210
29
    NC_var **vpp = ncap->value;
211
29
    NC_var *const *const end = &vpp[ncap->nelems];
212
48.4k
    for( /*NADA*/; vpp < end; vpp++)
213
48.3k
    {
214
48.3k
      free_NC_var(*vpp);
215
48.3k
      *vpp = NULL;
216
48.3k
    }
217
29
  }
218
29
  ncap->nelems = 0;
219
29
}
220
221
222
/*
223
 * Free NC_vararray values.
224
 * formerly
225
NC_free_array()
226
 */
227
void
228
free_NC_vararrayV(NC_vararray *ncap)
229
134
{
230
134
  assert(ncap != NULL);
231
232
134
  if(ncap->nalloc == 0)
233
104
    return;
234
235
30
  NC_hashmapfree(ncap->hashmap);
236
30
  ncap->hashmap = NULL;
237
238
30
  assert(ncap->value != NULL);
239
240
30
  free_NC_vararrayV0(ncap);
241
242
30
  free(ncap->value);
243
30
  ncap->value = NULL;
244
30
  ncap->nalloc = 0;
245
30
}
246
247
248
int
249
dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
250
0
{
251
0
  int status = NC_NOERR;
252
253
0
  assert(ref != NULL);
254
0
  assert(ncap != NULL);
255
256
0
  if(ref->nelems != 0)
257
0
  {
258
0
    const size_t sz = ref->nelems * sizeof(NC_var *);
259
0
    ncap->value = (NC_var **) malloc(sz);
260
0
    if(ncap->value == NULL)
261
0
      return NC_ENOMEM;
262
0
    (void) memset(ncap->value, 0, sz);
263
0
    ncap->nalloc = ref->nelems;
264
0
  }
265
266
0
  ncap->nelems = 0;
267
0
  {
268
0
    NC_var **vpp = ncap->value;
269
0
    const NC_var **drpp = (const NC_var **)ref->value;
270
0
    NC_var *const *const end = &vpp[ref->nelems];
271
0
    for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++)
272
0
    {
273
0
      *vpp = dup_NC_var(*drpp);
274
0
      if(*vpp == NULL)
275
0
      {
276
0
        status = NC_ENOMEM;
277
0
        break;
278
0
      }
279
0
    }
280
0
  }
281
282
0
  if(status != NC_NOERR)
283
0
  {
284
0
    free_NC_vararrayV(ncap);
285
0
    return status;
286
0
  }
287
288
0
  assert(ncap->nelems == ref->nelems);
289
290
0
  return NC_NOERR;
291
0
}
292
293
294
/*
295
 * Add a new handle on the end of an array of handles
296
 * Formerly
297
NC_incr_array(array, tail)
298
 */
299
static int
300
incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp)
301
0
{
302
0
  NC_var **vp;
303
304
0
  assert(ncap != NULL);
305
306
0
  if(ncap->nalloc == 0)
307
0
  {
308
0
    assert(ncap->nelems == 0);
309
0
    vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
310
0
    if(vp == NULL)
311
0
      return NC_ENOMEM;
312
0
    ncap->value = vp;
313
0
    ncap->nalloc = NC_ARRAY_GROWBY;
314
315
0
    ncap->hashmap = NC_hashmapnew(0);
316
0
  }
317
0
  else if(ncap->nelems +1 > ncap->nalloc)
318
0
  {
319
0
    vp = (NC_var **) realloc(ncap->value,
320
0
      (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
321
0
    if(vp == NULL)
322
0
      return NC_ENOMEM;
323
0
    ncap->value = vp;
324
0
    ncap->nalloc += NC_ARRAY_GROWBY;
325
0
  }
326
327
0
  if(newelemp != NULL)
328
0
  {
329
0
    NC_hashmapadd(ncap->hashmap, (uintptr_t)ncap->nelems, newelemp->name->cp, strlen(newelemp->name->cp));
330
0
    ncap->value[ncap->nelems] = newelemp;
331
0
    ncap->nelems++;
332
0
  }
333
0
  return NC_NOERR;
334
0
}
335
336
337
static NC_var *
338
elem_NC_vararray(const NC_vararray *ncap, size_t elem)
339
0
{
340
0
  assert(ncap != NULL);
341
    /* cast needed for braindead systems with signed size_t */
342
0
  if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
343
0
    return NULL;
344
345
0
  assert(ncap->value != NULL);
346
347
0
  return ncap->value[elem];
348
0
}
349
350
351
/* End vararray per se */
352
353
354
/*
355
 * Step thru NC_VARIABLE array, seeking match on name.
356
 * Return varid or -1 on not found.
357
 * *varpp is set to the appropriate NC_var.
358
 * Formerly (sort of) NC_hvarid
359
 */
360
int
361
NC_findvar(const NC_vararray *ncap, const char *uname, NC_var **varpp)
362
0
{
363
0
  int hash_var_id = -1;
364
0
  uintptr_t data;
365
0
  char *name = NULL;
366
367
0
  assert(ncap != NULL);
368
369
0
  if(ncap->nelems == 0)
370
0
      goto done;
371
372
  /* normalized version of uname */
373
0
        if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name))
374
0
      goto done;
375
376
0
  if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0)
377
0
      goto done;
378
379
0
  hash_var_id = (int)data;
380
0
        if (varpp != NULL)
381
0
    *varpp = ncap->value[hash_var_id];
382
0
done:
383
0
  if(name != NULL) free(name);
384
0
  return(hash_var_id); /* Normal return */
385
0
}
386
387
/*
388
 * For a netcdf type
389
 *  return the size of one element in the external representation.
390
 * Note that arrays get rounded up to X_ALIGN boundaries.
391
 * Formerly
392
NC_xtypelen
393
 * See also ncx_len()
394
 */
395
size_t
396
ncx_szof(nc_type type)
397
0
{
398
0
  switch(type){
399
0
  case NC_BYTE:
400
0
  case NC_CHAR:
401
0
  case NC_UBYTE:
402
0
    return(1);
403
0
  case NC_SHORT :
404
0
    return(2);
405
0
  case NC_INT:
406
0
    return X_SIZEOF_INT;
407
0
  case NC_FLOAT:
408
0
    return X_SIZEOF_FLOAT;
409
0
  case NC_DOUBLE :
410
0
    return X_SIZEOF_DOUBLE;
411
0
  case NC_USHORT :
412
0
    return X_SIZEOF_USHORT;
413
0
  case NC_UINT :
414
0
    return X_SIZEOF_UINT;
415
0
  case NC_INT64 :
416
0
    return X_SIZEOF_INT64;
417
0
  case NC_UINT64 :
418
0
    return X_SIZEOF_UINT64;
419
0
  default:
420
    /* 37824 Ignore */
421
0
          assert("ncx_szof invalid type" == 0);
422
0
          return 0;
423
0
  }
424
0
}
425
426
427
/*
428
 * 'compile' the shape and len of a variable
429
 *  Formerly
430
NC_var_shape(var, dims)
431
 */
432
int
433
NC_var_shape(NC_var *varp, const NC_dimarray *dims)
434
0
{
435
0
  size_t *shp, *op;
436
0
  off_t *dsp;
437
0
  int *ip = NULL;
438
0
  const NC_dim *dimp;
439
0
  off_t product = 1;
440
441
0
  varp->xsz = ncx_szof(varp->type);
442
443
0
  if(varp->ndims == 0 || varp->dimids == NULL)
444
0
  {
445
0
    goto out;
446
0
  }
447
448
  /*
449
   * use the user supplied dimension indices
450
   * to determine the shape
451
   */
452
0
  for(ip = varp->dimids, op = varp->shape
453
0
          ; ip < &varp->dimids[varp->ndims]; ip++, op++)
454
0
  {
455
0
    if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
456
0
      return NC_EBADDIM;
457
458
0
    dimp = elem_NC_dimarray(dims, (size_t)*ip);
459
0
    *op = dimp->size;
460
0
    if(*op == NC_UNLIMITED && ip != varp->dimids)
461
0
      return NC_EUNLIMPOS;
462
0
  }
463
464
  /*
465
   * Compute the dsizes
466
   */
467
        /* ndims is > 0 here */
468
0
  for(shp = varp->shape + varp->ndims -1,
469
0
        dsp = varp->dsizes + varp->ndims -1;
470
0
      shp >= varp->shape;
471
0
      shp--, dsp--)
472
0
  {
473
      /*if(!(shp == varp->shape && IS_RECVAR(varp)))*/
474
0
      if( shp != NULL && (shp != varp->shape || !IS_RECVAR(varp)))
475
0
    {
476
0
          if( ((off_t)(*shp)) <= OFF_T_MAX / product )
477
0
      {
478
0
              product *= (*shp > 0 ? *shp : 1);
479
0
      } else
480
0
      {
481
0
              product = OFF_T_MAX ;
482
0
      }
483
0
    }
484
0
      *dsp = product;
485
0
  }
486
487
488
0
out :
489
490
    /*
491
     * For CDF-1 and CDF-2 formats, the total number of array elements
492
     * cannot exceed 2^32, unless this variable is the last fixed-size
493
     * variable, there is no record variable, and the file starting
494
     * offset of this variable is less than 2GiB.
495
     * This will be checked in NC_check_vlens() during NC_endef()
496
     */
497
0
    varp->len = product * varp->xsz;
498
0
    if (varp->len % 4 > 0)
499
0
        varp->len += 4 - varp->len % 4; /* round up */
500
501
#if 0
502
  arrayp("\tshape", varp->ndims, varp->shape);
503
  arrayp("\tdsizes", varp->ndims, varp->dsizes);
504
#endif
505
0
  return NC_NOERR;
506
0
}
507
508
/*
509
 * Check whether variable size is less than or equal to vlen_max,
510
 * without overflowing in arithmetic calculations.  If OK, return 1,
511
 * else, return 0.  For CDF1 format or for CDF2 format on non-LFS
512
 * platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
513
 * systems with LFS it should be 2^32 - 4.
514
 */
515
int
516
0
NC_check_vlen(NC_var *varp, long long vlen_max) {
517
0
    size_t ii;
518
0
    long long prod=varp->xsz; /* product of xsz and dimensions so far */
519
520
0
    assert(varp != NULL);
521
0
    for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndims; ii++) {
522
0
      if(!varp->shape)
523
0
        return 0; /* Shape is undefined/NULL. */
524
0
      if ((long long)varp->shape[ii] > vlen_max / prod) {
525
0
        return 0;   /* size in bytes won't fit in a 32-bit int */
526
0
      }
527
0
      prod *= varp->shape[ii];
528
0
    }
529
0
    return 1;     /* OK */
530
0
}
531
532
533
/*! Look up a variable by varid.
534
 *
535
 * Given a valid ncp structure and varid, return the var.
536
 *
537
 * Formerly NC_hlookupvar()
538
 *
539
 * @param[in] ncp NC3_INFO data structure.
540
 * @param[in] varid The varid key for the var we are looking up.
541
 * @param[out] varp Data structure to contain the varp pointer.
542
 * @return Error code, if one exists, 0 otherwise.
543
 */
544
545
int NC_lookupvar(NC3_INFO* ncp, int varid, NC_var **varp)
546
0
{
547
0
  if(varid == NC_GLOBAL)
548
0
  {
549
      /* Global is error in this context */
550
0
      return NC_EGLOBAL;
551
0
  }
552
553
0
  if(varp)
554
0
    *varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
555
0
  else
556
0
    return NC_ENOTVAR;
557
558
0
  if(*varp == NULL)
559
0
    return NC_ENOTVAR;
560
561
0
  return NC_NOERR;
562
563
0
}
564
565
566
/* Public */
567
568
int
569
NC3_def_var( int ncid, const char *name, nc_type type,
570
   int ndims, const int *dimids, int *varidp)
571
0
{
572
0
  int status;
573
0
  NC *nc;
574
0
  NC3_INFO* ncp;
575
0
  int varid;
576
0
  NC_var *varp = NULL;
577
578
0
  status = NC_check_id(ncid, &nc);
579
0
  if(status != NC_NOERR)
580
0
    return status;
581
0
  ncp = NC3_DATA(nc);
582
583
0
  if(!NC_indef(ncp))
584
0
  {
585
0
    return NC_ENOTINDEFINE;
586
0
  }
587
588
0
  status = NC_check_name(name);
589
0
  if(status != NC_NOERR)
590
0
    return status;
591
592
0
  status = nc3_cktype(nc->mode, type);
593
0
  if(status != NC_NOERR)
594
0
    return status;
595
596
0
        if (ndims > NC_MAX_VAR_DIMS) return NC_EMAXDIMS;
597
598
    /* cast needed for braindead systems with signed size_t */
599
0
  if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
600
0
  {
601
0
    return NC_EINVAL;
602
0
  }
603
604
0
  varid = NC_findvar(&ncp->vars, name, &varp);
605
0
  if(varid != -1)
606
0
  {
607
0
    return NC_ENAMEINUSE;
608
0
  }
609
610
0
  varp = new_NC_var(name, type, ndims, dimids);
611
0
  if(varp == NULL)
612
0
    return NC_ENOMEM;
613
614
0
  status = NC_var_shape(varp, &ncp->dims);
615
0
  if(status != NC_NOERR)
616
0
  {
617
0
    free_NC_var(varp);
618
0
    return status;
619
0
  }
620
621
0
  status = incr_NC_vararray(&ncp->vars, varp);
622
0
  if(status != NC_NOERR)
623
0
  {
624
0
    free_NC_var(varp);
625
0
    return status;
626
0
  }
627
628
0
  if(varidp != NULL)
629
0
    *varidp = (int)ncp->vars.nelems -1; /* varid */
630
631
  /* set the variable's fill mode */
632
0
  if (NC_dofill(ncp))
633
0
    varp->no_fill = 0;
634
0
  else
635
0
    varp->no_fill = 1;
636
637
0
  return NC_NOERR;
638
0
}
639
640
641
int
642
NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
643
0
{
644
0
  int status;
645
0
  NC *nc;
646
0
  NC3_INFO* ncp;
647
0
  NC_var *varp;
648
0
  int varid;
649
650
0
  status = NC_check_id(ncid, &nc);
651
0
  if(status != NC_NOERR)
652
0
    return status;
653
0
  ncp = NC3_DATA(nc);
654
655
0
  varid = NC_findvar(&ncp->vars, name, &varp);
656
0
  if(varid == -1)
657
0
  {
658
0
    return NC_ENOTVAR;
659
0
  }
660
661
0
  *varid_ptr = varid;
662
0
  return NC_NOERR;
663
0
}
664
665
666
int
667
NC3_inq_var(int ncid,
668
  int varid,
669
  char *name,
670
  nc_type *typep,
671
  int *ndimsp,
672
  int *dimids,
673
  int *nattsp,
674
  int *no_fillp,
675
  void *fill_valuep)
676
0
{
677
0
  int status;
678
0
  NC *nc;
679
0
  NC3_INFO* ncp;
680
0
  NC_var *varp;
681
0
  size_t ii;
682
683
0
  status = NC_check_id(ncid, &nc);
684
0
  if(status != NC_NOERR)
685
0
    return status;
686
0
  ncp = NC3_DATA(nc);
687
688
0
  varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
689
0
  if(varp == NULL)
690
0
    return NC_ENOTVAR;
691
692
0
  if(name != NULL)
693
0
  {
694
0
    (void) strncpy(name, varp->name->cp, varp->name->nchars);
695
0
    name[varp->name->nchars] = 0;
696
0
  }
697
698
0
  if(typep != 0)
699
0
    *typep = varp->type;
700
0
  if(ndimsp != 0)
701
0
  {
702
0
    *ndimsp = (int) varp->ndims;
703
0
  }
704
0
  if(dimids != 0)
705
0
  {
706
0
    for(ii = 0; ii < varp->ndims; ii++)
707
0
    {
708
0
      dimids[ii] = varp->dimids[ii];
709
0
    }
710
0
  }
711
0
  if(nattsp != 0)
712
0
  {
713
0
    *nattsp = (int) varp->attrs.nelems;
714
0
  }
715
716
0
  if (no_fillp != NULL) *no_fillp = varp->no_fill;
717
718
0
  if (fill_valuep != NULL) {
719
0
    status = nc_get_att(ncid, varid, _FillValue, fill_valuep);
720
0
    if (status != NC_NOERR && status != NC_ENOTATT)
721
0
      return status;
722
0
    if (status == NC_ENOTATT) {
723
0
      status = NC3_inq_default_fill_value(varp->type, fill_valuep);
724
0
      if (status != NC_NOERR) return status;
725
0
    }
726
0
  }
727
728
0
  return NC_NOERR;
729
0
}
730
731
int
732
NC3_rename_var(int ncid, int varid, const char *unewname)
733
0
{
734
0
  int status = NC_NOERR;
735
0
  NC *nc;
736
0
  NC3_INFO* ncp;
737
0
  uintptr_t intdata;
738
0
  NC_var *varp;
739
0
  NC_string *old, *newStr;
740
0
  int other;
741
0
  char *newname = NULL; /* normalized */
742
743
0
  status = NC_check_id(ncid, &nc);
744
0
  if(status != NC_NOERR)
745
0
      goto done;
746
0
  ncp = NC3_DATA(nc);
747
748
0
  if(NC_readonly(ncp))
749
0
      {status = NC_EPERM; goto done;}
750
751
0
  status = NC_check_name(unewname);
752
0
  if(status != NC_NOERR)
753
0
      goto done;
754
755
  /* check for name in use */
756
0
  other = NC_findvar(&ncp->vars, unewname, &varp);
757
0
  if(other != -1)
758
0
      {status = NC_ENAMEINUSE; goto done;}
759
760
0
  status = NC_lookupvar(ncp, varid, &varp);
761
0
  if(status != NC_NOERR)
762
0
      goto done; /* invalid varid */
763
764
0
  old = varp->name;
765
0
        status = nc_utf8_normalize((const unsigned char *)unewname,(unsigned char **)&newname);
766
0
        if(status != NC_NOERR)
767
0
      goto done;
768
0
  if(NC_indef(ncp))
769
0
  {
770
    /* Remove old name from hashmap; add new... */
771
          /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
772
0
    NC_hashmapremove(ncp->vars.hashmap,old->cp,strlen(old->cp),NULL);
773
0
    newStr = new_NC_string(strlen(newname),newname);
774
0
    if(newStr == NULL)
775
0
        {status = NC_ENOMEM; goto done;}
776
0
    varp->name = newStr;
777
0
    intdata = (uintptr_t)varid;
778
0
    NC_hashmapadd(ncp->vars.hashmap, intdata, varp->name->cp, strlen(varp->name->cp));
779
0
    free_NC_string(old);
780
0
    goto done;
781
0
  }
782
783
  /* else, not in define mode */
784
  /* If new name is longer than old, then complain,
785
           but otherwise, no change (test is same as set_NC_string)*/
786
0
  if(varp->name->nchars < strlen(newname))
787
0
      {status = NC_ENOTINDEFINE; goto done;}
788
789
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
790
  /* Remove old name from hashmap; add new... */
791
0
        NC_hashmapremove(ncp->vars.hashmap,old->cp,strlen(old->cp),NULL);
792
793
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
794
0
  status = set_NC_string(varp->name, newname);
795
0
  if(status != NC_NOERR)
796
0
    goto done;
797
798
0
  intdata = (uintptr_t)varid;
799
0
  NC_hashmapadd(ncp->vars.hashmap, intdata, varp->name->cp, strlen(varp->name->cp));
800
801
0
  set_NC_hdirty(ncp);
802
803
0
  if(NC_doHsync(ncp))
804
0
  {
805
0
    status = NC_sync(ncp);
806
0
    if(status != NC_NOERR)
807
0
      goto done;
808
0
  }
809
0
done:
810
0
  if(newname) free(newname);
811
0
  return status;
812
0
}
813
814
int
815
NC3_def_var_fill(int ncid,
816
  int varid,
817
  int no_fill,
818
  const void *fill_value)
819
0
{
820
0
  int status;
821
0
  NC *nc;
822
0
  NC3_INFO* ncp;
823
0
  NC_var *varp;
824
825
0
  status = NC_check_id(ncid, &nc);
826
0
  if(status != NC_NOERR)
827
0
    return status;
828
0
  ncp = NC3_DATA(nc);
829
830
0
  if(NC_readonly(ncp))
831
0
  {
832
0
    return NC_EPERM;
833
0
  }
834
835
0
  if(!NC_indef(ncp))
836
0
  {
837
0
    return NC_ENOTINDEFINE;
838
0
  }
839
840
0
  varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
841
0
  if(varp == NULL)
842
0
    return NC_ENOTVAR;
843
844
0
  if (no_fill)
845
0
    varp->no_fill = 1;
846
0
  else
847
0
    varp->no_fill = 0;
848
849
  /* Are we setting a fill value? */
850
0
  if (fill_value != NULL && !varp->no_fill) {
851
852
    /* If there's a _FillValue attribute, delete it. */
853
0
    status = NC3_del_att(ncid, varid, _FillValue);
854
0
    if (status != NC_NOERR && status != NC_ENOTATT)
855
0
      return status;
856
857
    /* Create/overwrite attribute _FillValue */
858
0
    status = NC3_put_att(ncid, varid, _FillValue, varp->type, 1, fill_value, varp->type);
859
0
    if (status != NC_NOERR) return status;
860
0
  }
861
862
0
  return NC_NOERR;
863
0
}