Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/drc.c
Line
Count
Source
1
/*
2
Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
3
See COPYRIGHT for license information.
4
*/
5
6
#include "config.h"
7
#include <stddef.h>
8
#ifdef HAVE_UNISTD_H
9
#include <unistd.h>
10
#endif
11
#ifdef HAVE_STDARG_H
12
#include <stdarg.h>
13
#endif
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <assert.h>
18
19
#include "netcdf.h"
20
#include "ncbytes.h"
21
#include "ncuri.h"
22
#include "ncrc.h"
23
#include "nclog.h"
24
#include "ncauth.h"
25
#include "ncpathmgr.h"
26
#include "nc4internal.h"
27
#include "ncs3sdk.h"
28
#include "ncdispatch.h"
29
#include "ncutil.h"
30
31
#undef NOREAD
32
33
#undef DRCDEBUG
34
#undef LEXDEBUG
35
#undef PARSEDEBUG
36
37
0
#define RTAG ']'
38
0
#define LTAG '['
39
40
#undef MEMCHECK
41
#define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {}
42
43
/* Forward */
44
static int NC_rcload(void);
45
static char* rcreadline(char** nextlinep);
46
static void rctrim(char* text);
47
static void rcorder(NClist* rc);
48
static int rccompile(const char* path);
49
static int rcequal(NCRCentry* e1, NCRCentry* e2);
50
static int rclocatepos(const char* key, const char* hostport, const char* urlpath);
51
static struct NCRCentry* rclocate(const char* key, const char* hostport, const char* urlpath);
52
static int rcsearch(const char* prefix, const char* rcname, char** pathp);
53
static void rcfreeentries(NClist* rc);
54
static void rcfreeentry(NCRCentry* t);
55
#ifdef DRCDEBUG
56
static void storedump(char* msg, NClist* entrys);
57
#endif
58
59
/* Define default rc files and aliases, also defines load order*/
60
static const char* rcfilenames[] = {".ncrc", ".daprc", ".dodsrc", NULL};
61
62
static int NCRCinitialized = 0;
63
64
/**************************************************/
65
/* User API */
66
67
/**
68
The most common case is to get the most general value for a key,
69
where most general means that the urlpath and hostport are null
70
So this function returns the value associated with the key
71
where the .rc entry has the simple form "key=value".
72
If that entry is not found, then return NULL.
73
74
@param key table entry key field
75
@param  table entry key field
76
@return value matching the key -- caller frees
77
@return NULL if no entry of the form key=value exists
78
*/
79
char*
80
nc_rc_get(const char* key)
81
0
{
82
0
    NCglobalstate* ncg = NULL;
83
0
    char* value = NULL;
84
85
0
    if(!NC_initialized) nc_initialize();
86
87
0
    ncg = NC_getglobalstate();
88
0
    assert(ncg != NULL && ncg->rcinfo != NULL && ncg->rcinfo->entries != NULL);
89
0
    if(ncg->rcinfo->ignore) goto done;
90
0
    value = NC_rclookup(key,NULL,NULL);
91
0
done:
92
0
    value = nulldup(value);   
93
0
    return value;
94
0
}
95
96
/**
97
Set simple key=value in .rc table.
98
Will overwrite any existing value.
99
100
@param key
101
@param value 
102
@return NC_NOERR if success
103
@return NC_EINVAL if fail
104
*/
105
int
106
nc_rc_set(const char* key, const char* value)
107
0
{
108
0
    int stat = NC_NOERR;
109
0
    NCglobalstate* ncg = NULL;
110
111
0
    if(!NC_initialized) nc_initialize();
112
113
0
    ncg = NC_getglobalstate();
114
0
    assert(ncg != NULL && ncg->rcinfo != NULL && ncg->rcinfo->entries != NULL);
115
0
    if(ncg->rcinfo->ignore) goto done;;
116
0
    stat = NC_rcfile_insert(key,NULL,NULL,value);
117
0
done:
118
0
    return stat;
119
0
}
120
121
/**************************************************/
122
/* External Entry Points */
123
124
/*
125
Initialize defaults and load:
126
* .ncrc
127
* .dodsrc
128
* ${HOME}/.aws/config
129
* ${HOME}/.aws/credentials
130
131
For debugging support, it is possible
132
to change where the code looks for the .aws directory.
133
This is set by the environment variable NC_TEST_AWS_DIR.
134
135
*/
136
137
void
138
ncrc_initialize(void)
139
1
{
140
1
    if(NCRCinitialized) return;
141
1
    NCRCinitialized = 1; /* prevent recursion */
142
143
1
#ifndef NOREAD
144
1
    {
145
1
    int stat = NC_NOERR;
146
1
    NCglobalstate* ncg = NC_getglobalstate();
147
    /* Load entrys */
148
1
    if((stat = NC_rcload())) {
149
0
        nclog(NCLOGWARN,".rc loading failed");
150
0
    }
151
    /* Load .aws/config &/ credentials */
152
1
    if((stat = NC_aws_load_credentials(ncg))) {
153
1
        nclog(NCLOGWARN,"AWS config file not loaded");
154
1
    }
155
1
    }
156
1
#endif
157
1
}
158
159
static void
160
ncrc_setrchome(void)
161
1
{
162
1
    const char* tmp = NULL;
163
1
    NCglobalstate* ncg = NC_getglobalstate();
164
1
    assert(ncg && ncg->home);
165
1
    if(ncg->rcinfo->rchome) return;
166
1
    tmp = getenv(NCRCENVHOME);
167
1
    if(tmp == NULL || strlen(tmp) == 0)
168
1
  tmp = ncg->home;
169
1
    ncg->rcinfo->rchome = strdup(tmp);
170
#ifdef DRCDEBUG
171
    fprintf(stderr,"ncrc_setrchome: %s\n",ncg->rcinfo->rchome);
172
#endif
173
1
}
174
175
void
176
NC_rcclear(NCRCinfo* info)
177
1
{
178
1
    if(info == NULL) return;
179
1
    nullfree(info->rcfile);
180
1
    nullfree(info->rchome);
181
1
    rcfreeentries(info->entries);
182
1
    NC_s3freeprofilelist(info->s3profiles);
183
1
}
184
185
static void
186
rcfreeentry(NCRCentry* t)
187
0
{
188
0
  nullfree(t->host);
189
0
  nullfree(t->urlpath);
190
0
  nullfree(t->key);
191
0
  nullfree(t->value);
192
0
  free(t);
193
0
}
194
195
static void
196
rcfreeentries(NClist* rc)
197
1
{
198
1
    size_t i;
199
1
    for(i=0;i<nclistlength(rc);i++) {
200
0
  NCRCentry* t = (NCRCentry*)nclistget(rc,i);
201
0
  rcfreeentry(t);
202
0
    }
203
1
    nclistfree(rc);
204
1
}
205
206
/* locate, read and compile the rc files, if any */
207
static int
208
NC_rcload(void)
209
1
{
210
1
    size_t i;
211
1
    int ret = NC_NOERR;
212
1
    char* path = NULL;
213
1
    NCglobalstate* globalstate = NULL;
214
1
    NClist* rcfileorder = nclistnew();
215
216
1
    if(!NCRCinitialized) ncrc_initialize();
217
1
    globalstate = NC_getglobalstate();
218
219
1
    if(globalstate->rcinfo->ignore) {
220
0
        nclog(NCLOGNOTE,".rc file loading suppressed");
221
0
  goto done;
222
0
    }
223
1
    if(globalstate->rcinfo->loaded) goto done;
224
225
    /* locate the configuration files in order of use:
226
       1. Specified by NCRCENV_RC environment variable.
227
       2. If NCRCENV_RC is not set then merge the set of rc files in this order:
228
    1. $HOME/.ncrc
229
    2. $HOME/.dodsrc
230
    3. $CWD/.ncrc
231
    4. $CWD/.dodsrc
232
    Entries in later files override any of the earlier files
233
    */
234
1
    if(globalstate->rcinfo->rcfile != NULL) { /* always use this */
235
0
  nclistpush(rcfileorder,strdup(globalstate->rcinfo->rcfile));
236
1
    } else {
237
1
  const char** rcname;
238
1
  const char* dirnames[3];
239
1
  const char** dir;
240
241
        /* Make sure rcinfo.rchome is defined */
242
1
  ncrc_setrchome();
243
1
  dirnames[0] = globalstate->rcinfo->rchome;
244
1
  dirnames[1] = globalstate->cwd;
245
1
  dirnames[2] = NULL;
246
247
3
        for(dir=dirnames;*dir;dir++) {
248
8
      for(rcname=rcfilenames;*rcname;rcname++) {
249
6
          ret = rcsearch(*dir,*rcname,&path);
250
6
    if(ret == NC_NOERR && path != NULL)
251
0
        nclistpush(rcfileorder,path);
252
6
    path = NULL;
253
6
      }
254
2
  }
255
1
    }
256
1
    for(i=0;i<nclistlength(rcfileorder);i++) {
257
0
  path = (char*)nclistget(rcfileorder,i);
258
0
  if((ret=rccompile(path))) {
259
0
      nclog(NCLOGWARN, "Error parsing %s\n",path);
260
0
      ret = NC_NOERR; /* ignore it */
261
0
      goto done;
262
0
  }
263
0
    }
264
265
1
done:
266
1
    globalstate->rcinfo->loaded = 1; /* even if not exists */
267
1
    nclistfreeall(rcfileorder);
268
1
    return (ret);
269
1
}
270
271
/**
272
 * Locate a entry by property key.
273
 * If duplicate keys, first takes precedence.
274
 * @param key to lookup
275
 * @param hostport to use for lookup
276
 * @param urlpath to use for lookup
277
 * @return the value of the key or NULL if not found.
278
 */
279
char*
280
NC_rclookup(const char* key, const char* hostport, const char* urlpath)
281
1
{
282
1
    struct NCRCentry* entry = NULL;
283
1
    if(!NCRCinitialized) ncrc_initialize();
284
1
    entry = rclocate(key,hostport,urlpath);
285
1
    return (entry == NULL ? NULL : entry->value);
286
1
}
287
288
/**
289
 * Locate a entry by property key and uri.
290
 * If duplicate keys, first takes precedence.
291
 */
292
char*
293
NC_rclookupx(NCURI* uri, const char* key)
294
0
{
295
0
    char* hostport = NULL;
296
0
    char* result = NULL;
297
298
0
    hostport = NC_combinehostport(uri);
299
0
    result = NC_rclookup(key,hostport,uri->path);
300
0
    nullfree(hostport);
301
0
    return result;
302
0
}
303
304
#if 0
305
/*!
306
Set the absolute path to use for the rc file.
307
WARNING: this MUST be called before any other
308
call in order for this to take effect.
309
310
\param[in] rcfile The path to use. If NULL then do not use any rcfile.
311
312
\retval OC_NOERR if the request succeeded.
313
\retval OC_ERCFILE if the file failed to load
314
*/
315
316
int
317
NC_set_rcfile(const char* rcfile)
318
{
319
    int stat = NC_NOERR;
320
    FILE* f = NULL;
321
    NCglobalstate* globalstate = NC_getglobalstate();
322
323
    if(rcfile != NULL && strlen(rcfile) == 0)
324
  rcfile = NULL;
325
    f = NCfopen(rcfile,"r");
326
    if(f == NULL) {
327
  stat = NC_ERCFILE;
328
        goto done;
329
    }
330
    fclose(f);
331
    NC_rcclear(globalstate->rcinfo);
332
    globalstate->rcinfo->rcfile = strdup(rcfile);
333
    /* Clear globalstate->rcinfo */
334
    NC_rcclear(&globalstate->rcinfo);
335
    /* (re) load the rcfile and esp the entriestore*/
336
    stat = NC_rcload();
337
done:
338
    return stat;
339
}
340
#endif
341
342
/**************************************************/
343
/* RC processing functions */
344
345
static char*
346
rcreadline(char** nextlinep)
347
0
{
348
0
    char* line;
349
0
    char* p;
350
351
0
    line = (p = *nextlinep);
352
0
    if(*p == '\0') return NULL; /*signal done*/
353
0
    for(;*p;p++) {
354
0
  if(*p == '\r' && p[1] == '\n') *p = '\0';
355
0
  else if(*p == '\n') break;
356
0
    }
357
0
    *p++ = '\0'; /* null terminate line; overwrite newline */
358
0
    *nextlinep = p;
359
0
    return line;
360
0
}
361
362
/* Trim TRIMCHARS from both ends of text; */
363
static void
364
rctrim(char* text)
365
0
{
366
0
    char* p;
367
0
    char* q;
368
0
    size_t len = 0;
369
370
0
    if(text == NULL || *text == '\0') return;
371
372
0
    len = strlen(text);
373
374
    /* elide upto first non-trimchar */
375
0
    for(q=text,p=text;*p;p++) {
376
0
  if(*p != ' ' && *p != '\t' && *p != '\r') {*q++ = *p;}
377
0
    }
378
0
    len = strlen(p);
379
    /* locate last non-trimchar */
380
0
    if(len > 0) {
381
0
        for(size_t i = len; i-->0;) {
382
0
      p = &text[i];
383
0
      if(*p != ' ' && *p != '\t' && *p != '\r') {break;}
384
0
      *p = '\0'; /* elide trailing trimchars */
385
0
        }
386
0
    }
387
0
}
388
389
/* Order the entries: those with urls must be first,
390
   but otherwise relative order does not matter.
391
*/
392
static void
393
rcorder(NClist* rc)
394
0
{
395
0
    size_t i;
396
0
    size_t len = nclistlength(rc);
397
0
    NClist* tmprc = NULL;
398
0
    if(rc == NULL || len == 0) return;
399
0
    tmprc = nclistnew();
400
    /* Two passes: 1) pull entries with host */
401
0
    for(i=0;i<len;i++) {
402
0
        NCRCentry* ti = nclistget(rc,i);
403
0
  if(ti->host == NULL) continue;
404
0
  nclistpush(tmprc,ti);
405
0
    }
406
    /* pass 2 pull entries without host*/
407
0
    for(i=0;i<len;i++) {
408
0
        NCRCentry* ti = nclistget(rc,i);
409
0
  if(ti->host != NULL) continue;
410
0
  nclistpush(tmprc,ti);
411
0
    }
412
    /* Move tmp to rc */
413
0
    nclistsetlength(rc,0);
414
0
    for(i=0;i<len;i++) {
415
0
        NCRCentry* ti = nclistget(tmprc,i);
416
0
  nclistpush(rc,ti);
417
0
    }
418
#ifdef DRCDEBUG
419
    storedump("reorder:",rc);
420
#endif
421
0
    nclistfree(tmprc);
422
0
}
423
424
/* Merge a entry store from a file*/
425
static int
426
rccompile(const char* filepath)
427
0
{
428
0
    int ret = NC_NOERR;
429
0
    NClist* rc = NULL;
430
0
    char* contents = NULL;
431
0
    NCbytes* tmp = ncbytesnew();
432
0
    NCURI* uri = NULL;
433
0
    char* nextline = NULL;
434
0
    NCglobalstate* globalstate = NC_getglobalstate();
435
0
    NCS3INFO s3;
436
437
0
    memset(&s3,0,sizeof(s3));
438
439
0
    if((ret=NC_readfile(filepath,tmp))) {
440
0
        nclog(NCLOGWARN, "Could not open configuration file: %s",filepath);
441
0
  goto done;
442
0
    }
443
0
    contents = ncbytesextract(tmp);
444
0
    if(contents == NULL) contents = strdup("");
445
    /* Either reuse or create new  */
446
0
    rc = globalstate->rcinfo->entries;
447
0
    if(rc == NULL) {
448
0
        rc = nclistnew();
449
0
        globalstate->rcinfo->entries = rc;
450
0
    }
451
0
    nextline = contents;
452
0
    for(;;) {
453
0
  char* line;
454
0
  char* key = NULL;
455
0
        char* value = NULL;
456
0
        char* host = NULL;
457
0
        char* urlpath = NULL;
458
0
  size_t llen;
459
0
        NCRCentry* entry;
460
461
0
  line = rcreadline(&nextline);
462
0
  if(line == NULL) break; /* done */
463
0
        rctrim(line);  /* trim leading and trailing blanks */
464
0
        if(line[0] == '#') continue; /* comment */
465
0
  if((llen=strlen(line)) == 0) continue; /* empty line */
466
0
  if(line[0] == LTAG) {
467
0
      char* url = ++line;
468
0
            char* rtag = strchr(line,RTAG);
469
0
            if(rtag == NULL) {
470
0
                nclog(NCLOGERR, "Malformed [url] in %s entry: %s",filepath,line);
471
0
    continue;
472
0
            }
473
0
            line = rtag + 1;
474
0
            *rtag = '\0';
475
            /* compile the url and pull out the host, port, and path */
476
0
            if(uri) ncurifree(uri);
477
0
            if(ncuriparse(url,&uri)) {
478
0
                nclog(NCLOGERR, "Malformed [url] in %s entry: %s",filepath,line);
479
0
    continue;
480
0
            }
481
0
      if(NC_iss3(uri,NULL)) {
482
0
           NCURI* newuri = NULL;
483
          /* Rebuild the url to S3 "path" format */
484
0
    NC_s3clear(&s3);
485
0
          if((ret = NC_s3urlrebuild(uri,&s3,&newuri))) goto done;
486
0
    ncurifree(uri);
487
0
    uri = newuri;
488
0
    newuri = NULL;
489
0
      }
490
      /* Get the host+port */
491
0
            ncbytesclear(tmp);
492
0
            ncbytescat(tmp,uri->host);
493
0
            if(uri->port != NULL) {
494
0
    ncbytesappend(tmp,':');
495
0
                ncbytescat(tmp,uri->port);
496
0
            }
497
0
            ncbytesnull(tmp);
498
0
            host = ncbytesextract(tmp);
499
0
      if(strlen(host)==0) /* nullify host */
500
0
    {free(host); host = NULL;}
501
      /* Get the url path part */
502
0
      urlpath = uri->path;
503
0
      if(urlpath && strlen(urlpath)==0) urlpath = NULL; /* nullify */
504
0
  }
505
        /* split off key and value */
506
0
        key=line;
507
0
        value = strchr(line, '=');
508
0
        if(value == NULL)
509
0
            value = line + strlen(line);
510
0
        else {
511
0
            *value = '\0';
512
0
            value++;
513
0
        }
514
  /* See if key already exists */
515
0
  entry = rclocate(key,host,urlpath);
516
0
  if(entry == NULL) {
517
0
      entry = (NCRCentry*)calloc(1,sizeof(NCRCentry));
518
0
      if(entry == NULL) {ret = NC_ENOMEM; goto done;}
519
0
      nclistpush(rc,entry);
520
0
      entry->host = host; host = NULL;
521
0
      entry->urlpath = nulldup(urlpath);
522
0
          entry->key = nulldup(key);
523
0
            rctrim(entry->host);
524
0
            rctrim(entry->urlpath);
525
0
            rctrim(entry->key);
526
0
  }
527
0
  nullfree(entry->value);
528
0
        entry->value = nulldup(value);
529
0
        rctrim(entry->value);
530
531
#ifdef DRCDEBUG
532
  fprintf(stderr,"rc: host=%s urlpath=%s key=%s value=%s\n",
533
    (entry->host != NULL ? entry->host : "<null>"),
534
    (entry->urlpath != NULL ? entry->urlpath : "<null>"),
535
    entry->key,entry->value);
536
#endif
537
0
  entry = NULL;
538
0
    }
539
#ifdef DRCDEBUG
540
    fprintf(stderr,"reorder.path=%s\n",filepath);
541
#endif
542
0
    rcorder(rc);
543
544
0
done:
545
0
    NC_s3clear(&s3);
546
0
    if(contents) free(contents);
547
0
    ncurifree(uri);
548
0
    ncbytesfree(tmp);
549
0
    return (ret);
550
0
}
551
552
/**
553
Encapsulate equality comparison: return 1|0
554
*/
555
static int
556
rcequal(NCRCentry* e1, NCRCentry* e2)
557
0
{
558
0
    int nulltest;
559
0
    if(e1->key == NULL || e2->key == NULL) return 0;
560
0
    if(strcmp(e1->key,e2->key) != 0) return 0;
561
    /* test hostport; take NULL into account*/
562
0
    nulltest = 0;
563
0
    if(e1->host == NULL) nulltest |= 1;
564
0
    if(e2->host == NULL) nulltest |= 2;
565
    /* Use host to decide if entry applies */
566
0
    switch (nulltest) {
567
0
    case 0: if(strcmp(e1->host,e2->host) != 0) {return 0;}  break;
568
0
    case 1: break;    /* .rc->host == NULL && candidate->host != NULL */
569
0
    case 2: return 0; /* .rc->host != NULL && candidate->host == NULL */
570
0
    case 3: break;    /* .rc->host == NULL && candidate->host == NULL */
571
0
    default: return 0;
572
0
    }
573
    /* test urlpath take NULL into account*/
574
0
    nulltest = 0;
575
0
    if(e1->urlpath == NULL) nulltest |= 1;
576
0
    if(e2->urlpath == NULL) nulltest |= 2;
577
0
    switch (nulltest) {
578
0
    case 0: if(strcmp(e1->urlpath,e2->urlpath) != 0) {return 0;} break;
579
0
    case 1: break;    /* .rc->urlpath == NULL && candidate->urlpath != NULL */
580
0
    case 2: return 0; /* .rc->urlpath != NULL && candidate->urlpath == NULL */
581
0
    case 3: break;    /* .rc->urlpath == NULL && candidate->urlpath == NULL */
582
0
    default: return 0;
583
0
    }
584
0
    return 1;
585
0
}
586
587
/**
588
 * (Internal) Locate a entry by property key and host+port (may be null) and urlpath (may be null)
589
 * If duplicate keys, first takes precedence.
590
 */
591
static int
592
rclocatepos(const char* key, const char* hostport, const char* urlpath)
593
1
{
594
1
    size_t i;
595
1
    NCglobalstate* globalstate = NC_getglobalstate();
596
1
    struct NCRCinfo* info = globalstate->rcinfo;
597
1
    NCRCentry* entry = NULL;
598
1
    NCRCentry candidate;
599
1
    NClist* rc = info->entries;
600
601
1
    if(info->ignore) return -1;
602
603
1
    candidate.key = (char*)key;
604
1
    candidate.value = (char*)NULL;
605
1
    candidate.host = (char*)hostport;
606
1
    candidate.urlpath = (char*)urlpath;
607
608
1
    for(i=0;i<nclistlength(rc);i++) {
609
0
      entry = (NCRCentry*)nclistget(rc,i);
610
0
      if(rcequal(entry,&candidate)) return (int)i;
611
0
    }
612
1
    return -1;
613
1
}
614
615
/**
616
 * (Internal) Locate a entry by property key and host+port (may be null or "").
617
 * If duplicate keys, first takes precedence.
618
 */
619
static struct NCRCentry*
620
rclocate(const char* key, const char* hostport, const char* urlpath)
621
1
{
622
1
    int pos;
623
1
    NCglobalstate* globalstate = NC_getglobalstate();
624
1
    struct NCRCinfo* info = globalstate->rcinfo;
625
626
1
    if(globalstate->rcinfo->ignore) return NULL;
627
1
    if(key == NULL || info == NULL) return NULL;
628
1
    pos = rclocatepos(key,hostport,urlpath);
629
1
    if(pos < 0) return NULL;
630
0
    return NC_rcfile_ith(info,(size_t)pos);
631
1
}
632
633
/**
634
 * Locate rc file by searching in directory prefix.
635
 */
636
static
637
int
638
rcsearch(const char* prefix, const char* rcname, char** pathp)
639
6
{
640
6
    char* path = NULL;
641
6
    FILE* f = NULL;
642
6
    size_t plen = (prefix?strlen(prefix):0);
643
6
    size_t rclen = strlen(rcname);
644
6
    int ret = NC_NOERR;
645
646
6
    size_t pathlen = plen+rclen+1+1; /*+1 for '/' +1 for nul */
647
6
    path = (char*)malloc(pathlen); /* +1 for nul*/
648
6
    if(path == NULL) {ret = NC_ENOMEM; goto done;}
649
6
    snprintf(path, pathlen, "%s/%s", prefix, rcname);
650
    /* see if file is readable */
651
6
    f = NCfopen(path,"r");
652
6
    if(f != NULL)
653
0
        nclog(NCLOGNOTE, "Found rc file=%s",path);
654
6
done:
655
6
    if(f == NULL || ret != NC_NOERR) {
656
6
  nullfree(path);
657
6
  path = NULL;
658
6
    }
659
6
    if(f != NULL)
660
0
      fclose(f);
661
6
    if(pathp != NULL)
662
6
      *pathp = path;
663
0
    else {
664
0
      nullfree(path);
665
0
      path = NULL;
666
0
    }
667
6
    errno = 0; /* silently ignore errors */
668
6
    return (ret);
669
6
}
670
671
int
672
NC_rcfile_insert(const char* key, const char* hostport, const char* urlpath, const char* value)
673
0
{
674
0
    int ret = NC_NOERR;
675
    /* See if this key already defined */
676
0
    struct NCRCentry* entry = NULL;
677
0
    NCglobalstate* globalstate = NULL;
678
0
    NClist* rc = NULL;
679
680
0
    if(!NCRCinitialized) ncrc_initialize();
681
682
0
    if(key == NULL || value == NULL)
683
0
        {ret = NC_EINVAL; goto done;}
684
685
0
    globalstate = NC_getglobalstate();
686
0
    rc = globalstate->rcinfo->entries;
687
688
0
    if(rc == NULL) {
689
0
  rc = nclistnew();
690
0
        globalstate->rcinfo->entries = rc;
691
0
  if(rc == NULL) {ret = NC_ENOMEM; goto done;}
692
0
    }
693
0
    entry = rclocate(key,hostport,urlpath);
694
0
    if(entry == NULL) {
695
0
  entry = (NCRCentry*)calloc(1,sizeof(NCRCentry));
696
0
  if(entry == NULL) {ret = NC_ENOMEM; goto done;}
697
0
  entry->key = strdup(key);
698
0
  entry->value = NULL;
699
0
        rctrim(entry->key);
700
0
        entry->host = nulldup(hostport);
701
0
        rctrim(entry->host);
702
0
        entry->urlpath = nulldup(urlpath);
703
0
        rctrim(entry->urlpath);
704
0
  nclistpush(rc,entry);
705
0
    }
706
0
    if(entry->value != NULL) free(entry->value);
707
0
    entry->value = strdup(value);
708
0
    rctrim(entry->value);
709
#ifdef DRCDEBUG
710
    storedump("NC_rcfile_insert",rc);
711
#endif    
712
0
done:
713
0
    return ret;
714
0
}
715
716
/* Obtain the count of number of entries */
717
size_t
718
NC_rcfile_length(NCRCinfo* info)
719
0
{
720
0
    return nclistlength(info->entries);
721
0
}
722
723
/* Obtain the ith entry; return NULL if out of range */
724
NCRCentry*
725
NC_rcfile_ith(NCRCinfo* info, size_t i)
726
0
{
727
0
    if(i >= nclistlength(info->entries))
728
0
  return NULL;
729
0
    return (NCRCentry*)nclistget(info->entries,i);
730
0
}
731
732
733
#ifdef DRCDEBUG
734
static void
735
storedump(char* msg, NClist* entries)
736
{
737
    int i;
738
739
    if(msg != NULL) fprintf(stderr,"%s\n",msg);
740
    if(entries == NULL || nclistlength(entries)==0) {
741
        fprintf(stderr,"<EMPTY>\n");
742
        return;
743
    }
744
    for(i=0;i<nclistlength(entries);i++) {
745
  NCRCentry* t = (NCRCentry*)nclistget(entries,i);
746
        fprintf(stderr,"\t%s\t%s\t%s\n",
747
                ((t->host == NULL || strlen(t->host)==0)?"--":t->host),t->key,t->value);
748
    }
749
    fflush(stderr);
750
}
751
#endif