2 * Copyright (c) 1999, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.1 1999/10/12 11:56:40 bp Exp $
33 * $DragonFly: src/lib/libncp/ncpl_rcfile.c,v 1.2 2003/06/17 04:26:50 dillon Exp $
35 #include <sys/types.h>
36 #include <sys/queue.h>
45 #include <netncp/ncp_lib.h>
46 #include <netncp/ncp_rcfile.h>
47 #include <netncp/ncp_cfg.h>
49 #define NWFS_CFG_FILE NCP_PREFIX"/etc/nwfs.conf"
51 struct rcfile
*ncp_rc
= NULL
;
53 SLIST_HEAD(rcfile_head
, rcfile
);
54 static struct rcfile_head pf_head
= {NULL
};
56 int rc_merge(char *filename
,struct rcfile
**rcfile
);
57 static struct rcfile
* rc_find(char *filename
);
58 static struct rcsection
*rc_findsect(struct rcfile
*rcp
, char *sectname
);
59 static struct rcsection
*rc_addsect(struct rcfile
*rcp
, char *sectname
);
60 static int rc_sect_free(struct rcsection
*rsp
);
61 static struct rckey
*rc_sect_findkey(struct rcsection
*rsp
, char *keyname
);
62 static struct rckey
*rc_sect_addkey(struct rcsection
*rsp
, char *name
, char *value
);
63 static void rc_key_free(struct rckey
*p
);
64 static void rc_parse(struct rcfile
*rcp
);
68 * open rcfile and load its content, if already open - return previous handle
71 rc_open(char *filename
,char *mode
,struct rcfile
**rcfile
) {
75 rcp
= rc_find(filename
);
80 f
= fopen (filename
, mode
);
83 rcp
= malloc(sizeof(struct rcfile
));
88 bzero(rcp
, sizeof(struct rcfile
));
89 rcp
->rf_name
= strdup (filename
);
91 SLIST_INSERT_HEAD(&pf_head
, rcp
, rf_next
);
98 rc_merge(char *filename
,struct rcfile
**rcfile
) {
99 struct rcfile
*rcp
= *rcfile
;
103 return rc_open(filename
,"r",rcfile
);
105 f
= fopen (filename
, "r");
117 rc_close(struct rcfile
*rcp
) {
118 struct rcsection
*p
,*n
;
121 for(p
= SLIST_FIRST(&rcp
->rf_sect
);p
;) {
123 p
= SLIST_NEXT(p
,rs_next
);
127 SLIST_REMOVE(&pf_head
, rcp
, rcfile
, rf_next
);
132 static struct rcfile
*
133 rc_find(char *filename
) {
136 SLIST_FOREACH(p
, &pf_head
, rf_next
)
137 if (strcmp (filename
, p
->rf_name
)==0)
142 static struct rcsection
*
143 rc_findsect(struct rcfile
*rcp
, char *sectname
) {
146 SLIST_FOREACH(p
, &rcp
->rf_sect
, rs_next
)
147 if (strcmp(p
->rs_name
, sectname
)==0)
152 static struct rcsection
*
153 rc_addsect(struct rcfile
*rcp
, char *sectname
) {
156 p
= rc_findsect(rcp
, sectname
);
158 p
= malloc(sizeof(*p
));
160 p
->rs_name
= strdup(sectname
);
161 SLIST_INIT(&p
->rs_keys
);
162 SLIST_INSERT_HEAD(&rcp
->rf_sect
, p
, rs_next
);
167 rc_sect_free(struct rcsection
*rsp
) {
170 for(p
= SLIST_FIRST(&rsp
->rs_keys
);p
;) {
172 p
= SLIST_NEXT(p
,rk_next
);
180 static struct rckey
*
181 rc_sect_findkey(struct rcsection
*rsp
, char *keyname
) {
184 SLIST_FOREACH(p
, &rsp
->rs_keys
, rk_next
)
185 if (strcmp(p
->rk_name
, keyname
)==0)
190 static struct rckey
*
191 rc_sect_addkey(struct rcsection
*rsp
, char *name
, char *value
) {
194 p
= rc_sect_findkey(rsp
, name
);
198 p
= malloc(sizeof(*p
));
200 SLIST_INSERT_HEAD(&rsp
->rs_keys
, p
, rk_next
);
201 p
->rk_name
= strdup(name
);
203 p
->rk_value
= value
? strdup(value
) : strdup("");
208 rc_sect_delkey(struct rcsection
*rsp
, struct rckey
*p
) {
210 SLIST_REMOVE(&rsp
->rs_keys
,p
,rckey
,rk_next
);
216 rc_key_free(struct rckey
*p
){
222 enum { stNewLine
, stHeader
, stSkipToEOL
, stGetKey
, stGetValue
};
225 rc_parse(struct rcfile
*rcp
) {
227 int state
= stNewLine
, c
;
228 struct rcsection
*rsp
= NULL
;
229 struct rckey
*rkp
= NULL
;
231 char *next
= buf
, *last
= &buf
[sizeof(buf
)-1];
233 while ((c
= getc (f
)) != EOF
) {
236 if (state
== stNewLine
) {
239 continue; /* skip leading junk */
245 if (c
== '#' || c
== ';') {
247 } else { /* something meaningfull */
251 if (state
== stSkipToEOL
|| next
== last
) {/* ignore long lines */
258 if (state
== stHeader
) {
262 rsp
= rc_addsect(rcp
, buf
);
268 if (state
== stGetKey
) {
269 if (c
== ' ' || c
== '\t')/* side effect: 'key name='*/
270 continue; /* become 'keyname=' */
271 if (c
== '\n') { /* silently ignore ... */
281 fprintf(stderr
, "Key '%s' defined before section\n", buf
);
285 rkp
= rc_sect_addkey(rsp
, buf
, NULL
);
290 /* only stGetValue left */
291 if (state
!= stGetValue
) {
292 fprintf(stderr
, "Well, I can't parse file '%s'\n",rcp
->rf_name
);
300 rkp
->rk_value
= strdup(buf
);
304 if (c
== EOF
&& state
== stGetValue
) {
306 rkp
->rk_value
= strdup(buf
);
312 rc_getstringptr(struct rcfile
*rcp
,char *section
, char *key
,char **dest
) {
313 struct rcsection
*rsp
;
317 rsp
= rc_findsect(rcp
, section
);
318 if (!rsp
) return ENOENT
;
319 rkp
= rc_sect_findkey(rsp
,key
);
320 if (!rkp
) return ENOENT
;
321 *dest
= rkp
->rk_value
;
326 rc_getstring(struct rcfile
*rcp
,char *section
, char *key
,int maxlen
,char *dest
) {
330 error
= rc_getstringptr(rcp
, section
, key
, &value
);
331 if (error
) return error
;
332 if (strlen(value
) >= maxlen
) {
333 fprintf(stderr
, "line too long for key '%s' in section '%s', max = %d\n",key
, section
, maxlen
);
341 rc_getint(struct rcfile
*rcp
,char *section
, char *key
,int *value
) {
342 struct rcsection
*rsp
;
345 rsp
= rc_findsect(rcp
, section
);
346 if (!rsp
) return ENOENT
;
347 rkp
= rc_sect_findkey(rsp
,key
);
348 if (!rkp
) return ENOENT
;
350 *value
= strtol(rkp
->rk_value
,NULL
,0);
352 fprintf(stderr
, "invalid int value '%s' for key '%s' in section '%s'\n",rkp
->rk_value
,key
,section
);
363 rc_getbool(struct rcfile
*rcp
,char *section
, char *key
,int *value
) {
364 struct rcsection
*rsp
;
368 rsp
= rc_findsect(rcp
, section
);
369 if (!rsp
) return ENOENT
;
370 rkp
= rc_sect_findkey(rsp
,key
);
371 if (!rkp
) return ENOENT
;
373 while (*p
&& isspace(*p
)) p
++;
374 if (*p
== '0' || strcasecmp(p
,"no") == 0 || strcasecmp(p
,"false") == 0) {
378 if (*p
== '1' || strcasecmp(p
,"yes") == 0 || strcasecmp(p
,"true") == 0) {
382 fprintf(stderr
, "invalid boolean value '%s' for key '%s' in section '%s' \n",p
, key
, section
);
387 * first read ~/.nwfsrc, next try to merge NWFS_CFG_FILE
390 ncp_open_rcfile(void) {
394 home
= getenv("HOME");
396 fn
= malloc(strlen(home
) + 20);
397 sprintf(fn
, "%s/.nwfsrc", home
);
398 error
= rc_open(fn
,"r",&ncp_rc
);
401 error
= rc_merge(NWFS_CFG_FILE
, &ncp_rc
);
402 if( ncp_rc
== NULL
) {
403 printf("Warning: no cfg files found.\n");