Coverage Report

Created: 2026-07-16 06:49

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