Coverage Report

Created: 2025-10-28 07:06

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