nandsim_rcfile.c revision 259065
1190372Sedwin/*
2153761Swollman * Copyright (c) 1999, Boris Popov
364499Swollman * All rights reserved.
42742Swollman *
52742Swollman * Redistribution and use in source and binary forms, with or without
62742Swollman * modification, are permitted provided that the following conditions
72742Swollman * are met:
8158421Swollman * 1. Redistributions of source code must retain the above copyright
92742Swollman *    notice, this list of conditions and the following disclaimer.
10158421Swollman * 2. Redistributions in binary form must reproduce the above copyright
11158421Swollman *    notice, this list of conditions and the following disclaimer in the
122742Swollman *    documentation and/or other materials provided with the distribution.
1386222Swollman * 3. Neither the name of the author nor the names of any co-contributors
1420094Swollman *    may be used to endorse or promote products derived from this software
1520094Swollman *    without specific prior written permission.
1620094Swollman *
1720094Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1820094Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19158421Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20158421Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2120094Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2219878Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2319878Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2419878Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2519878Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2619878Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2719878Swollman * SUCH DAMAGE.
2819878Swollman *
2919878Swollman * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp
3058787Sru */
3158787Sru
3258787Sru#include <sys/cdefs.h>
3358787Sru__FBSDID("$FreeBSD: releng/10.0/usr.sbin/nandsim/nandsim_rcfile.c 235537 2012-05-17 10:11:18Z gber $");
3458787Sru#include <sys/types.h>
3558787Sru#include <sys/queue.h>
3658787Sru#include <ctype.h>
3758787Sru#include <errno.h>
3858787Sru#include <stdio.h>
3958787Sru#include <string.h>
4058787Sru#include <stdlib.h>
4158787Sru#include <pwd.h>
4258787Sru#include <unistd.h>
4358787Sru
4458787Sru#include "nandsim_rcfile.h"
4558787Sru
4658787SruSLIST_HEAD(rcfile_head, rcfile);
4758787Srustatic struct rcfile_head pf_head = {NULL};
482742Swollmanstatic struct rcsection *rc_findsect(struct rcfile *rcp,
492742Swollman    const char *sectname, int sect_id);
502742Swollmanstatic struct rcsection *rc_addsect(struct rcfile *rcp,
512742Swollman    const char *sectname);
522742Swollmanstatic int rc_sect_free(struct rcsection *rsp);
532742Swollmanstatic struct rckey *rc_sect_findkey(struct rcsection *rsp,
542742Swollman    const char *keyname);
5519878Swollmanstatic struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
562742Swollman    char *value);
572742Swollmanstatic void rc_key_free(struct rckey *p);
582742Swollmanstatic void rc_parse(struct rcfile *rcp);
5919878Swollman
602742Swollmanstatic struct rcfile* rc_find(const char *filename);
612742Swollman
62149514Swollman/*
6321217Swollman * open rcfile and load its content, if already open - return previous handle
649908Swollman */
659908Swollmanint
662742Swollmanrc_open(const char *filename, const char *mode,struct rcfile **rcfile)
6719878Swollman{
6819878Swollman	struct rcfile *rcp;
6919878Swollman	FILE *f;
7019878Swollman	rcp = rc_find(filename);
7119878Swollman	if (rcp) {
7219878Swollman		*rcfile = rcp;
7319878Swollman		return (0);
7419878Swollman	}
7519878Swollman	f = fopen (filename, mode);
7619878Swollman	if (f == NULL)
7719878Swollman		return errno;
7819878Swollman	rcp = malloc(sizeof(struct rcfile));
7919878Swollman	if (rcp == NULL) {
8019878Swollman		fclose(f);
8119878Swollman		return ENOMEM;
8219878Swollman	}
8393799Swollman	bzero(rcp, sizeof(struct rcfile));
8458787Sru	rcp->rf_name = strdup(filename);
8558787Sru	rcp->rf_f = f;
8619878Swollman	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
8719878Swollman	rc_parse(rcp);
8819878Swollman	*rcfile = rcp;
899908Swollman	return (0);
90149514Swollman}
919908Swollman
929908Swollmanint
939908Swollmanrc_close(struct rcfile *rcp)
9421217Swollman{
9519878Swollman	struct rcsection *p,*n;
9619878Swollman
979908Swollman	fclose(rcp->rf_f);
98149514Swollman	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
999908Swollman		n = p;
1009908Swollman		p = SLIST_NEXT(p,rs_next);
1019908Swollman		rc_sect_free(n);
1029908Swollman	}
10358787Sru	free(rcp->rf_name);
10458787Sru	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
10558787Sru	free(rcp);
10664499Swollman	return (0);
10764499Swollman}
108175034Sedwin
109175034Sedwinstatic struct rcfile*
110175034Sedwinrc_find(const char *filename)
111175034Sedwin{
112175034Sedwin	struct rcfile *p;
11358787Sru
11458787Sru	SLIST_FOREACH(p, &pf_head, rf_next)
11567578Swollman		if (strcmp (filename, p->rf_name) == 0)
11658787Sru			return (p);
11758787Sru	return (0);
11858787Sru}
119149514Swollman
12064499Swollman/* Find section with given name and id */
12164499Swollmanstatic struct rcsection *
12264499Swollmanrc_findsect(struct rcfile *rcp, const char *sectname, int sect_id)
12364499Swollman{
12486222Swollman	struct rcsection *p;
12586222Swollman
12686222Swollman	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
12786222Swollman		if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id)
12886222Swollman			return (p);
12986222Swollman	return (NULL);
13086222Swollman}
13186222Swollman
13286222Swollmanstatic struct rcsection *
13386222Swollmanrc_addsect(struct rcfile *rcp, const char *sectname)
13486222Swollman{
13586222Swollman	struct rcsection *p;
13686222Swollman	int id = 0;
13786222Swollman	p = rc_findsect(rcp, sectname, 0);
13886222Swollman	if (p) {
13986222Swollman		/*
14086222Swollman		 * If section with that name already exists -- add one more,
14186222Swollman		 * same named, but with different id (higher by one)
14286222Swollman		 */
14386222Swollman		while (p != NULL) {
14486222Swollman			id = p->rs_id + 1;
14586222Swollman			p = rc_findsect(rcp, sectname, id);
14686222Swollman		}
147175034Sedwin	}
148175034Sedwin	p = malloc(sizeof(*p));
149175034Sedwin	if (!p)
150175034Sedwin		return (NULL);
151175034Sedwin	p->rs_name = strdup(sectname);
152175034Sedwin	p->rs_id = id;
153175034Sedwin	SLIST_INIT(&p->rs_keys);
154175034Sedwin	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
155175034Sedwin	return (p);
156175034Sedwin}
157175034Sedwin
158175034Sedwinstatic int
159175034Sedwinrc_sect_free(struct rcsection *rsp)
160175034Sedwin{
161175034Sedwin	struct rckey *p,*n;
162175034Sedwin
163175034Sedwin	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
164175034Sedwin		n = p;
165175034Sedwin		p = SLIST_NEXT(p,rk_next);
166175034Sedwin		rc_key_free(n);
167183066Sedwin	}
168183066Sedwin	free(rsp->rs_name);
169183066Sedwin	free(rsp);
170183066Sedwin	return (0);
171183066Sedwin}
172183066Sedwin
173183066Sedwinstatic struct rckey *
174183066Sedwinrc_sect_findkey(struct rcsection *rsp, const char *keyname)
175183066Sedwin{
176183066Sedwin	struct rckey *p;
177183066Sedwin
178183066Sedwin	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
179183066Sedwin		if (strcmp(p->rk_name, keyname)==0)
180183864Sedwin			return (p);
181183864Sedwin	return (NULL);
182183864Sedwin}
183183864Sedwin
184183864Sedwinstatic struct rckey *
185183864Sedwinrc_sect_addkey(struct rcsection *rsp, const char *name, char *value)
186183864Sedwin{
187183864Sedwin	struct rckey *p;
188183864Sedwin	p = rc_sect_findkey(rsp, name);
189183864Sedwin	if (p) {
190183864Sedwin		free(p->rk_value);
191183864Sedwin	} else {
192183864Sedwin		p = malloc(sizeof(*p));
193183864Sedwin		if (!p)
194183864Sedwin			return (NULL);
195183864Sedwin		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
196184406Sedwin		p->rk_name = strdup(name);
197184406Sedwin	}
198184406Sedwin	p->rk_value = value ? strdup(value) : strdup("");
199184406Sedwin	return (p);
200184406Sedwin}
201184406Sedwin
202184406Sedwinstatic void
203184406Sedwinrc_key_free(struct rckey *p)
204184406Sedwin{
205184406Sedwin	free(p->rk_value);
206184406Sedwin	free(p->rk_name);
207184406Sedwin	free(p);
208184406Sedwin}
209184406Sedwin
210184406Sedwinenum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
211184406Sedwin
212184406Sedwinstatic void
213184406Sedwinrc_parse(struct rcfile *rcp)
214184406Sedwin{
215184406Sedwin	FILE *f = rcp->rf_f;
216175034Sedwin	int state = stNewLine, c;
217175034Sedwin	struct rcsection *rsp = NULL;
218183066Sedwin	struct rckey *rkp = NULL;
219175034Sedwin	char buf[2048];
220136638Swollman	char *next = buf, *last = &buf[sizeof(buf)-1];
221136638Swollman
222136638Swollman	while ((c = getc (f)) != EOF) {
223136638Swollman		if (c == '\r')
224136638Swollman			continue;
225136638Swollman		if (state == stNewLine) {
226136638Swollman			next = buf;
22793799Swollman			if (isspace(c))
228158421Swollman				continue;	/* skip leading junk */
22993799Swollman			if (c == '[') {
230158421Swollman				state = stHeader;
23193799Swollman				rsp = NULL;
23293799Swollman				continue;
233158421Swollman			}
234136638Swollman			if (c == '#' || c == ';') {
235136638Swollman				state = stSkipToEOL;
236136638Swollman			} else {		/* something meaningful */
237136638Swollman				state = stGetKey;
238136638Swollman			}
239136638Swollman		}
240136638Swollman		if (state == stSkipToEOL || next == last) {/* ignore long lines */
241136638Swollman			if (c == '\n') {
242136638Swollman				state = stNewLine;
243136638Swollman				next = buf;
244136638Swollman			}
245136638Swollman			continue;
246136638Swollman		}
247136638Swollman		if (state == stHeader) {
248136638Swollman			if (c == ']') {
249136638Swollman				*next = 0;
250136638Swollman				next = buf;
251136638Swollman				rsp = rc_addsect(rcp, buf);
252136638Swollman				state = stSkipToEOL;
253136638Swollman			} else
254136638Swollman				*next++ = c;
255136638Swollman			continue;
256136638Swollman		}
257136638Swollman		if (state == stGetKey) {
258136638Swollman			if (c == ' ' || c == '\t')/* side effect: 'key name='*/
259136638Swollman				continue;	  /* become 'keyname='	     */
260136638Swollman			if (c == '\n') {	  /* silently ignore ... */
261136638Swollman				state = stNewLine;
262136638Swollman				continue;
263136638Swollman			}
264136638Swollman			if (c != '=') {
265136638Swollman				*next++ = c;
266136638Swollman				continue;
267136638Swollman			}
268136638Swollman			*next = 0;
269136638Swollman			if (rsp == NULL) {
270136638Swollman				fprintf(stderr, "Key '%s' defined before "
271136638Swollman				    "section\n", buf);
272136638Swollman				state = stSkipToEOL;
273136638Swollman				continue;
274136638Swollman			}
275136638Swollman			rkp = rc_sect_addkey(rsp, buf, NULL);
276136638Swollman			next = buf;
277136638Swollman			state = stGetValue;
278136638Swollman			continue;
27993799Swollman		}
280177591Sedwin		/* only stGetValue left */
281177591Sedwin		if (state != stGetValue) {
282177591Sedwin			fprintf(stderr, "Well, I can't parse file "
283177591Sedwin			    "'%s'\n",rcp->rf_name);
284177591Sedwin			state = stSkipToEOL;
285177591Sedwin		}
286177591Sedwin		if (c != '\n') {
287177591Sedwin			*next++ = c;
288177591Sedwin			continue;
289177591Sedwin		}
290177591Sedwin		*next = 0;
291177591Sedwin		rkp->rk_value = strdup(buf);
292177591Sedwin		state = stNewLine;
293177591Sedwin		rkp = NULL;
294177591Sedwin	}	/* while */
295177591Sedwin	if (c == EOF && state == stGetValue) {
296177591Sedwin		*next = 0;
297177591Sedwin		rkp->rk_value = strdup(buf);
298177591Sedwin	}
299177591Sedwin}
300177591Sedwin
301177591Sedwinint
302177591Sedwinrc_getstringptr(struct rcfile *rcp, const char *section, int sect_id,
303177591Sedwin    const char *key, char **dest)
304177591Sedwin{
305177591Sedwin	struct rcsection *rsp;
306177591Sedwin	struct rckey *rkp;
307177591Sedwin
308177591Sedwin	*dest = NULL;
309177591Sedwin	rsp = rc_findsect(rcp, section, sect_id);
310177591Sedwin	if (!rsp)
311177591Sedwin		return (ENOENT);
312177591Sedwin	rkp = rc_sect_findkey(rsp,key);
313177591Sedwin	if (!rkp)
314177591Sedwin		return (ENOENT);
315177591Sedwin	*dest = rkp->rk_value;
316177591Sedwin	return (0);
317177591Sedwin}
318177591Sedwin
319177591Sedwinint
320177591Sedwinrc_getstring(struct rcfile *rcp, const char *section, int sect_id,
321177591Sedwin    const char *key, unsigned int maxlen, char *dest)
322177591Sedwin{
323177591Sedwin	char *value;
324177591Sedwin	int error;
325177591Sedwin
326177591Sedwin	error = rc_getstringptr(rcp, section, sect_id, key, &value);
327177591Sedwin	if (error)
328177591Sedwin		return (error);
329177591Sedwin	if (strlen(value) >= maxlen) {
330177591Sedwin		fprintf(stderr, "line too long for key '%s' in section '%s',"
331177591Sedwin		    "max = %d\n",key, section, maxlen);
332177591Sedwin		return (EINVAL);
333177591Sedwin	}
334177591Sedwin	strcpy(dest,value);
335177591Sedwin	return (0);
336177591Sedwin}
337177591Sedwin
338177591Sedwinint
339177591Sedwinrc_getint(struct rcfile *rcp, const char *section, int sect_id,
340177591Sedwin    const char *key, int *value)
341177591Sedwin{
342177591Sedwin	struct rcsection *rsp;
343177591Sedwin	struct rckey *rkp;
344177591Sedwin
345177591Sedwin	rsp = rc_findsect(rcp, section, sect_id);
346181421Sedwin	if (!rsp)
347158421Swollman		return (ENOENT);
348158421Swollman	rkp = rc_sect_findkey(rsp,key);
349181421Sedwin	if (!rkp)
350181421Sedwin		return (ENOENT);
351181421Sedwin	errno = 0;
352181421Sedwin	*value = strtol(rkp->rk_value,NULL,0);
353181421Sedwin	if (errno) {
354190372Sedwin		fprintf(stderr, "invalid int value '%s' for key '%s' in "
355190372Sedwin		    "section '%s'\n",rkp->rk_value,key,section);
356190372Sedwin		return (errno);
357190372Sedwin	}
35893799Swollman	return (0);
359190372Sedwin}
360190372Sedwin
361190372Sedwin/*
362190372Sedwin * 1,yes,true
363190372Sedwin * 0,no,false
364190372Sedwin */
365190372Sedwinint
366190372Sedwinrc_getbool(struct rcfile *rcp, const char *section, int sect_id,
367190372Sedwin    const char *key, int *value)
368190372Sedwin{
369190372Sedwin	struct rcsection *rsp;
370190372Sedwin	struct rckey *rkp;
371190372Sedwin	char *p;
372190372Sedwin
373190372Sedwin	rsp = rc_findsect(rcp, section, sect_id);
374190372Sedwin	if (!rsp)
375190372Sedwin		return (ENOENT);
376190372Sedwin	rkp = rc_sect_findkey(rsp,key);
377190372Sedwin	if (!rkp)
378190372Sedwin		return (ENOENT);
379190372Sedwin	p = rkp->rk_value;
380190372Sedwin	while (*p && isspace(*p)) p++;
381190372Sedwin	if (*p == '0' || strcasecmp(p,"no") == 0 ||
382190372Sedwin	    strcasecmp(p, "false") == 0 ||
383190372Sedwin	    strcasecmp(p, "off") == 0) {
384190372Sedwin		*value = 0;
385190372Sedwin		return (0);
386190372Sedwin	}
387190372Sedwin	if (*p == '1' || strcasecmp(p,"yes") == 0 ||
388190372Sedwin	    strcasecmp(p, "true") == 0 ||
389190372Sedwin	    strcasecmp(p, "on") == 0) {
390190372Sedwin		*value = 1;
391190372Sedwin		return (0);
392190372Sedwin	}
393190372Sedwin	fprintf(stderr, "invalid boolean value '%s' for key '%s' in section "
394190372Sedwin	    "'%s' \n",p, key, section);
395190372Sedwin	return (EINVAL);
396190372Sedwin}
397190372Sedwin
398190372Sedwin/* Count how many sections with given name exists in configuration. */
3992742Swollmanint rc_getsectionscount(struct rcfile *f, const char *sectname)
40020094Swollman{
401136638Swollman	struct rcsection *p;
402136638Swollman	int count = 0;
40393799Swollman
40419878Swollman	p = rc_findsect(f, sectname, 0);
40558787Sru	if (p) {
40693799Swollman		while (p != NULL) {
40793799Swollman			count = p->rs_id + 1;
408175034Sedwin			p = rc_findsect(f, sectname, count);
40920094Swollman		}
410184406Sedwin		return (count);
411184406Sedwin	} else
41220094Swollman		return (0);
413158421Swollman}
41493799Swollman
41593799Swollmanchar **
41693799Swollmanrc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id)
41793799Swollman{
41893799Swollman	struct rcsection *rsp;
41993799Swollman	struct rckey *p;
420136638Swollman	char **names_tbl;
42193799Swollman	int i = 0, count = 0;
42220094Swollman
42358787Sru	rsp = rc_findsect(rcp, sectname, sect_id);
42493799Swollman	if (rsp == NULL)
42593799Swollman		return (NULL);
42693799Swollman
42793799Swollman	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
428175034Sedwin		count++;
42920094Swollman
430184406Sedwin	names_tbl = malloc(sizeof(char *) * (count + 1));
431184406Sedwin	if (names_tbl == NULL)
432184406Sedwin		return (NULL);
433184406Sedwin
434184406Sedwin	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
435184406Sedwin		names_tbl[i++] = p->rk_name;
436184406Sedwin
437184406Sedwin	names_tbl[i] = NULL;
438184406Sedwin	return (names_tbl);
439184406Sedwin}
440184406Sedwin
441184406Sedwin