Coverage Report

Created: 2025-12-09 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/nclist.c
Line
Count
Source
1
/* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc.
2
   See the COPYRIGHT file for more information. */
3
#include <stddef.h>
4
#include <stdlib.h>
5
#include <stdio.h>
6
#include <string.h>
7
8
#include "nclist.h"
9
10
#undef HAVE_MEMMOVE
11
12
#if defined(_WIN32) && !defined(__MINGW32__)
13
#define strcasecmp _stricmp
14
#endif
15
16
#define NCLISTDEBUG 1
17
18
#ifndef TRUE
19
5.55k
#define TRUE 1
20
#endif
21
#ifndef FALSE
22
0
#define FALSE 0
23
#endif
24
25
1
#define DEFAULTALLOC 16
26
#define ALLOCINCR 16
27
28
/*Forward */
29
static void memmovex(void* dst, void* src, size_t len);
30
31
0
int nclistisnull(void* e) {return e == NULL;}
32
33
static int
34
nclistfail(void)
35
0
{
36
0
    fflush(stdout);
37
0
    fprintf(stderr,"NClist failure\n");
38
0
    fflush(stderr);
39
0
#ifdef NCLISTDEBUG
40
0
    abort();
41
0
#endif
42
0
    return FALSE;
43
0
}
44
45
NClist* nclistnew(void)
46
1.31k
{
47
1.31k
  NClist* l;
48
/*
49
  if(!ncinitialized) {
50
    memset((void*)&ncDATANULL,0,sizeof(void*));
51
    ncinitialized = 1;
52
  }
53
*/
54
1.31k
  l = (NClist*)calloc(1,sizeof(NClist));
55
1.31k
  if(l) {
56
1.31k
    l->alloc=0;
57
1.31k
    l->length=0;
58
1.31k
    l->content=NULL;
59
1.31k
    l->extendible = 1;
60
1.31k
  }
61
1.31k
  return l;
62
1.31k
}
63
64
int
65
nclistfree(NClist* l)
66
1.96k
{
67
1.96k
  if(l) {
68
1.31k
    l->alloc = 0;
69
1.31k
    if(l->extendible && l->content != NULL) {free(l->content); l->content = NULL;}
70
1.31k
    free(l);
71
1.31k
  }
72
1.96k
  return TRUE;
73
1.96k
}
74
75
/*
76
Free a list and its contents
77
*/
78
int
79
nclistfreeall(NClist* l)
80
1.63k
{
81
1.63k
    nclistclearall(l);
82
1.63k
    return nclistfree(l);
83
1.63k
}
84
85
/*
86
Free the contents of a list
87
*/
88
int
89
nclistclearall(NClist* l)
90
1.63k
{
91
1.63k
  size_t i,len;
92
1.63k
  if(l == NULL) return TRUE;
93
980
  len = l->length;
94
982
  for(i=0;i<len;i++) {
95
2
      void* value = l->content[i];
96
2
      if(value != NULL) free(value);
97
2
  }
98
980
  nclistsetlength(l,0);
99
980
  return TRUE;
100
1.63k
}
101
102
/*
103
Set allocated memory to newalloc elements.
104
If newalloc is zero, then just guarantee that l->content has memory allocated.
105
*/
106
int
107
nclistsetalloc(NClist* l, size_t newalloc)
108
981
{
109
981
  void** newcontent = NULL;
110
981
  size_t alloc;
111
981
  if(l == NULL) return nclistfail();
112
981
  if(newalloc == 0) newalloc = DEFAULTALLOC; /* force newalloc to be greater than 0 */
113
981
  if(l->alloc >= newalloc) {return TRUE;} /* already enough space */
114
  /* Iterate to find an allocation greater or equal to newalloc */
115
981
  alloc = l->alloc;
116
1.96k
  while(alloc < newalloc)
117
986
      alloc = (2*alloc + 1); /* Double until we have a suitable allocation; +1 in case alloc is zero*/
118
981
  newcontent=(void**)calloc(alloc,sizeof(void*));
119
981
  if(newcontent == NULL) return nclistfail(); /* out of memory */
120
  /* Copy data, if any,  to new contents */
121
981
  if(l->alloc > 0 && l->length > 0 && l->content != NULL)
122
0
    memcpy((void*)newcontent,(void*)l->content,sizeof(void*)*l->length);
123
981
  if(l->content != NULL) free(l->content); /* reclaim old contents */
124
981
  l->content = newcontent;
125
981
  l->alloc = alloc;
126
981
  return TRUE;
127
981
}
128
129
int
130
nclistsetlength(NClist* l, size_t newlen)
131
981
{
132
981
  if(l == NULL) return nclistfail();
133
981
  if(newlen >= l->alloc && !nclistsetalloc(l,newlen+1)) /* +1 in case newlen == l->alloc */
134
0
      return nclistfail();
135
981
  if(newlen > l->length) {
136
      /* clear any extension */
137
1
      memset(&l->content[l->length],0,(newlen - l->length)*sizeof(void*));
138
1
  }
139
981
  l->length = newlen;
140
981
  return TRUE;
141
981
}
142
143
void*
144
nclistget(const NClist* l, size_t index)
145
1
{
146
1
  if(l == NULL) return (nclistfail(),NULL);
147
1
  if(l->length == 0) return NULL;
148
1
  if(index >= l->length) return NULL;
149
1
  return l->content[index];
150
1
}
151
152
/* Insert at position i of l; will overwrite previous value;
153
   guarantees alloc and length
154
*/
155
int
156
nclistset(NClist* l, size_t index, void* elem)
157
0
{
158
0
  if(l == NULL) return nclistfail();
159
0
  if(!nclistsetalloc(l,index+1)) return nclistfail();
160
0
  if(index >= l->length) {
161
0
      if(!nclistsetlength(l,index+1)) return nclistfail();
162
0
  }
163
0
  l->content[index] = elem;
164
0
  return TRUE;
165
0
}
166
167
/* Insert at position i of l; will push up elements i..|seq|. */
168
int
169
nclistinsert(NClist* l, size_t index, void* elem)
170
0
{
171
0
  size_t i;
172
0
  if(l == NULL) return nclistfail();
173
0
  if(index > l->length) return nclistfail();
174
0
  nclistsetalloc(l,0);
175
0
  if(l->length > 0) {
176
0
    memmovex(l->content+(index+1),l->content+index,(l->length-index)*sizeof(void*));
177
#if 0
178
    for(i=l->length;i>index;i--) l->content[i] = l->content[i-1];
179
#endif
180
0
  }
181
0
  l->content[index] = elem;
182
0
  l->length++;
183
0
  return TRUE;
184
0
}
185
186
int
187
nclistpush(NClist* l, const void* elem)
188
1
{
189
1
  if(l == NULL) return nclistfail();
190
1
  if(l->content == NULL)
191
1
      nclistsetalloc(l,0);
192
1
  if(l->length >= l->alloc) nclistsetalloc(l,l->length+1);
193
1
  l->content[l->length] = (void*)elem;
194
1
  l->length++;
195
1
  return TRUE;
196
1
}
197
198
void*
199
nclistpop(NClist* l)
200
0
{
201
0
  if(l == NULL) return (nclistfail(),NULL);
202
0
  if(l->length == 0) return NULL;
203
0
  l->length--;
204
0
  return l->content[l->length];
205
0
}
206
207
void*
208
nclisttop(NClist* l)
209
0
{
210
0
  if(l == NULL) return (nclistfail(),NULL);
211
0
  if(l->length == 0) return NULL;
212
0
  return l->content[l->length - 1];
213
0
}
214
215
void*
216
nclistremove(NClist* l, size_t i)
217
0
{
218
0
  size_t len;
219
0
  void* elem;
220
0
  if(l == NULL) return (nclistfail(),NULL);
221
0
  if((len=l->length) == 0) return NULL;
222
0
  if(i >= len) return NULL;
223
0
  elem = l->content[i];
224
0
  memmovex(l->content+i,l->content+(i+1),(len-(i+1))*sizeof(void*));
225
#if 0  
226
  for(i+=1;i<len;i++) l->content[i-1] = l->content[i];
227
#endif
228
0
  l->length--;
229
0
  return elem;
230
0
}
231
232
/* Match on == */
233
int
234
nclistcontains(NClist* l, void* elem)
235
0
{
236
0
    size_t i;
237
0
    for(i=0;i<nclistlength(l);i++) {
238
0
  if(elem == nclistget(l,i)) return 1;
239
0
    }
240
0
    return 0;
241
0
}
242
243
/* Match on str(case)cmp */
244
int
245
nclistmatch(NClist* l, const char* elem, int casesensitive)
246
0
{
247
0
    size_t i;
248
0
    for(i=0;i<nclistlength(l);i++) {
249
0
  const char* candidate = (const char*)nclistget(l,i);
250
0
  int match;
251
0
  if(casesensitive)
252
0
      match = strcmp(elem,candidate);
253
0
  else
254
0
      match = strcasecmp(elem,candidate);
255
0
  if(match == 0) return 1;
256
0
    }
257
0
    return 0;
258
0
}
259
260
/* Remove element by value; only removes first encountered */
261
int
262
nclistelemremove(NClist* l, void* elem)
263
0
{
264
0
  size_t len;
265
0
  size_t i;
266
0
  int found = 0;
267
0
  if(l == NULL) return nclistfail();
268
0
  if((len=l->length) == 0) return 0;
269
0
  for(i=0;i<nclistlength(l);i++) {
270
0
    void* candidate = l->content[i];
271
0
    if(elem == candidate) {
272
0
  nclistremove(l,i);
273
0
        found = 1;
274
0
        break;
275
0
    }
276
0
  }
277
0
  return found;
278
0
}
279
280
/* Extends nclist to include a unique operator
281
   which remove duplicate values; NULL values removed
282
   return value is always 1.
283
*/
284
285
int
286
nclistunique(NClist* l)
287
0
{
288
0
    size_t i,j,k,len;
289
0
    void** content;
290
0
    if(l == NULL) return nclistfail();
291
0
    if(l->length == 0) return 1;
292
0
    len = l->length;
293
0
    content = l->content;
294
0
    for(i=0;i<len;i++) {
295
0
        for(j=i+1;j<len;j++) {
296
0
      if(content[i] == content[j]) {
297
    /* compress out jth element */
298
0
                for(k=j+1;k<len;k++) content[k-1] = content[k];
299
0
    len--;
300
0
      }
301
0
  }
302
0
    }
303
0
    l->length = len;
304
0
    return 1;
305
0
}
306
307
/* Duplicate a list and if deep is true, assume the contents
308
   are char** and duplicate those also */
309
NClist*
310
nclistclone(const NClist* l, int deep)
311
0
{
312
0
    NClist* clone = NULL;
313
0
    if(l == NULL) goto done;
314
0
    clone = nclistnew();
315
0
    nclistsetalloc(clone,l->length+1); /* make room for final null */
316
0
    if(!deep) {
317
0
        nclistsetlength(clone,l->length);
318
0
        memcpy((void*)clone->content,(void*)l->content,sizeof(void*)*l->length);
319
0
    } else { /*deep*/
320
0
  size_t i;
321
0
  for(i=0;i<nclistlength(l);i++) {
322
0
      char* dups = strdup(nclistget(l,i));
323
0
      if(dups == NULL) {nclistfreeall(clone); clone = NULL; goto done;}
324
0
      nclistpush(clone,dups);     
325
0
  }
326
0
    }
327
0
    clone->content[l->length] = (void*)0;
328
0
done:
329
0
    return clone;
330
0
}
331
332
void*
333
nclistextract(NClist* l)
334
0
{
335
0
    void* result = NULL;
336
0
    if(l) {
337
0
  result = l->content;
338
0
  l->alloc = 0;
339
0
  l->length = 0;
340
0
  l->content = NULL;
341
0
    }
342
0
    return result;
343
0
}
344
345
int
346
nclistsetcontents(NClist* l, void** contents, size_t alloc, size_t length)
347
0
{
348
0
    if(l == NULL) return nclistfail();
349
0
    if(l->extendible && l->content != NULL) {free(l->content);} else {l->content = NULL;}
350
0
    l->content = (void**)contents;
351
0
    l->length = length;
352
0
    l->alloc = alloc;
353
0
    l->extendible = 0;
354
0
    return 1;
355
0
}
356
357
/* Extends nclist to include a NULL that is not included
358
   in list length.
359
   return value is always 1.
360
*/
361
int
362
nclistnull(NClist* l)
363
0
{
364
0
    if(l == NULL) return nclistfail();
365
0
    if(l->length == 0) return 1;
366
0
    nclistpush(l,NULL);
367
0
    nclistsetlength(l,l->length-1);
368
0
    return 1;
369
0
}
370
371
/**************************************************/
372
/* Utility functions */
373
374
/**
375
Define an internal form of memmove if not
376
defined by platform.
377
@param dst where to store bytes
378
@param src source of bytes
379
@param len no. of bytes to move
380
@return void
381
*/
382
static void
383
memmovex(void* dst, void* src, size_t len)
384
0
{
385
0
    if(len == 0) return;
386
#ifdef HAVE_MEMMOVE
387
    memmove(dst,src,len*sizeof(char));
388
#else
389
0
    {
390
0
        char *d = dst;
391
0
        const char *s = src;
392
0
        if (d < s) {
393
0
            while (len--) {*d++ = *s++;}
394
0
        } else {
395
0
            d += len; /* Point to one past the end of destination */
396
0
            s += len; /* Point to one past the end of source */
397
0
            while (len--) {*(--d) = *(--s);} /* Decrement pointers and copy */
398
0
        }
399
0
    }
400
0
#endif
401
0
}
402