Coverage Report

Created: 2022-11-18 06:58

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