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