]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/nandsim/nandsim_rcfile.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / nandsim / nandsim_rcfile.c
1 /*
2  * Copyright (c) 1999, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * from: FreeBSD: src/lib/libncp/ncpl_rcfile.c,v 1.5 2007/01/09 23:27:39 imp Exp
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/queue.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <pwd.h>
42 #include <unistd.h>
43
44 #include "nandsim_rcfile.h"
45
46 SLIST_HEAD(rcfile_head, rcfile);
47 static struct rcfile_head pf_head = {NULL};
48 static struct rcsection *rc_findsect(struct rcfile *rcp,
49     const char *sectname, int sect_id);
50 static struct rcsection *rc_addsect(struct rcfile *rcp,
51     const char *sectname);
52 static int rc_sect_free(struct rcsection *rsp);
53 static struct rckey *rc_sect_findkey(struct rcsection *rsp,
54     const char *keyname);
55 static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
56     char *value);
57 static void rc_key_free(struct rckey *p);
58 static void rc_parse(struct rcfile *rcp);
59
60 static struct rcfile* rc_find(const char *filename);
61
62 /*
63  * open rcfile and load its content, if already open - return previous handle
64  */
65 int
66 rc_open(const char *filename, const char *mode,struct rcfile **rcfile)
67 {
68         struct rcfile *rcp;
69         FILE *f;
70         rcp = rc_find(filename);
71         if (rcp) {
72                 *rcfile = rcp;
73                 return (0);
74         }
75         f = fopen (filename, mode);
76         if (f == NULL)
77                 return errno;
78         rcp = malloc(sizeof(struct rcfile));
79         if (rcp == NULL) {
80                 fclose(f);
81                 return ENOMEM;
82         }
83         bzero(rcp, sizeof(struct rcfile));
84         rcp->rf_name = strdup(filename);
85         rcp->rf_f = f;
86         SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
87         rc_parse(rcp);
88         *rcfile = rcp;
89         return (0);
90 }
91
92 int
93 rc_close(struct rcfile *rcp)
94 {
95         struct rcsection *p,*n;
96
97         fclose(rcp->rf_f);
98         for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
99                 n = p;
100                 p = SLIST_NEXT(p,rs_next);
101                 rc_sect_free(n);
102         }
103         free(rcp->rf_name);
104         SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
105         free(rcp);
106         return (0);
107 }
108
109 static struct rcfile*
110 rc_find(const char *filename)
111 {
112         struct rcfile *p;
113
114         SLIST_FOREACH(p, &pf_head, rf_next)
115                 if (strcmp (filename, p->rf_name) == 0)
116                         return (p);
117         return (0);
118 }
119
120 /* Find section with given name and id */
121 static struct rcsection *
122 rc_findsect(struct rcfile *rcp, const char *sectname, int sect_id)
123 {
124         struct rcsection *p;
125
126         SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
127                 if (strcmp(p->rs_name, sectname) == 0 && p->rs_id == sect_id)
128                         return (p);
129         return (NULL);
130 }
131
132 static struct rcsection *
133 rc_addsect(struct rcfile *rcp, const char *sectname)
134 {
135         struct rcsection *p;
136         int id = 0;
137         p = rc_findsect(rcp, sectname, 0);
138         if (p) {
139                 /*
140                  * If section with that name already exists -- add one more,
141                  * same named, but with different id (higher by one)
142                  */
143                 while (p != NULL) {
144                         id = p->rs_id + 1;
145                         p = rc_findsect(rcp, sectname, id);
146                 }
147         }
148         p = malloc(sizeof(*p));
149         if (!p)
150                 return (NULL);
151         p->rs_name = strdup(sectname);
152         p->rs_id = id;
153         SLIST_INIT(&p->rs_keys);
154         SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
155         return (p);
156 }
157
158 static int
159 rc_sect_free(struct rcsection *rsp)
160 {
161         struct rckey *p,*n;
162
163         for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
164                 n = p;
165                 p = SLIST_NEXT(p,rk_next);
166                 rc_key_free(n);
167         }
168         free(rsp->rs_name);
169         free(rsp);
170         return (0);
171 }
172
173 static struct rckey *
174 rc_sect_findkey(struct rcsection *rsp, const char *keyname)
175 {
176         struct rckey *p;
177
178         SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
179                 if (strcmp(p->rk_name, keyname)==0)
180                         return (p);
181         return (NULL);
182 }
183
184 static struct rckey *
185 rc_sect_addkey(struct rcsection *rsp, const char *name, char *value)
186 {
187         struct rckey *p;
188         p = rc_sect_findkey(rsp, name);
189         if (p) {
190                 free(p->rk_value);
191         } else {
192                 p = malloc(sizeof(*p));
193                 if (!p)
194                         return (NULL);
195                 SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
196                 p->rk_name = strdup(name);
197         }
198         p->rk_value = value ? strdup(value) : strdup("");
199         return (p);
200 }
201
202 static void
203 rc_key_free(struct rckey *p)
204 {
205         free(p->rk_value);
206         free(p->rk_name);
207         free(p);
208 }
209
210 enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
211
212 static void
213 rc_parse(struct rcfile *rcp)
214 {
215         FILE *f = rcp->rf_f;
216         int state = stNewLine, c;
217         struct rcsection *rsp = NULL;
218         struct rckey *rkp = NULL;
219         char buf[2048];
220         char *next = buf, *last = &buf[sizeof(buf)-1];
221
222         while ((c = getc (f)) != EOF) {
223                 if (c == '\r')
224                         continue;
225                 if (state == stNewLine) {
226                         next = buf;
227                         if (isspace(c))
228                                 continue;       /* skip leading junk */
229                         if (c == '[') {
230                                 state = stHeader;
231                                 rsp = NULL;
232                                 continue;
233                         }
234                         if (c == '#' || c == ';') {
235                                 state = stSkipToEOL;
236                         } else {                /* something meaningful */
237                                 state = stGetKey;
238                         }
239                 }
240                 if (state == stSkipToEOL || next == last) {/* ignore long lines */
241                         if (c == '\n') {
242                                 state = stNewLine;
243                                 next = buf;
244                         }
245                         continue;
246                 }
247                 if (state == stHeader) {
248                         if (c == ']') {
249                                 *next = 0;
250                                 next = buf;
251                                 rsp = rc_addsect(rcp, buf);
252                                 state = stSkipToEOL;
253                         } else
254                                 *next++ = c;
255                         continue;
256                 }
257                 if (state == stGetKey) {
258                         if (c == ' ' || c == '\t')/* side effect: 'key name='*/
259                                 continue;         /* become 'keyname='       */
260                         if (c == '\n') {          /* silently ignore ... */
261                                 state = stNewLine;
262                                 continue;
263                         }
264                         if (c != '=') {
265                                 *next++ = c;
266                                 continue;
267                         }
268                         *next = 0;
269                         if (rsp == NULL) {
270                                 fprintf(stderr, "Key '%s' defined before "
271                                     "section\n", buf);
272                                 state = stSkipToEOL;
273                                 continue;
274                         }
275                         rkp = rc_sect_addkey(rsp, buf, NULL);
276                         next = buf;
277                         state = stGetValue;
278                         continue;
279                 }
280                 /* only stGetValue left */
281                 if (state != stGetValue) {
282                         fprintf(stderr, "Well, I can't parse file "
283                             "'%s'\n",rcp->rf_name);
284                         state = stSkipToEOL;
285                 }
286                 if (c != '\n') {
287                         *next++ = c;
288                         continue;
289                 }
290                 *next = 0;
291                 rkp->rk_value = strdup(buf);
292                 state = stNewLine;
293                 rkp = NULL;
294         }       /* while */
295         if (c == EOF && state == stGetValue) {
296                 *next = 0;
297                 rkp->rk_value = strdup(buf);
298         }
299 }
300
301 int
302 rc_getstringptr(struct rcfile *rcp, const char *section, int sect_id,
303     const char *key, char **dest)
304 {
305         struct rcsection *rsp;
306         struct rckey *rkp;
307
308         *dest = NULL;
309         rsp = rc_findsect(rcp, section, sect_id);
310         if (!rsp)
311                 return (ENOENT);
312         rkp = rc_sect_findkey(rsp,key);
313         if (!rkp)
314                 return (ENOENT);
315         *dest = rkp->rk_value;
316         return (0);
317 }
318
319 int
320 rc_getstring(struct rcfile *rcp, const char *section, int sect_id,
321     const char *key, unsigned int maxlen, char *dest)
322 {
323         char *value;
324         int error;
325
326         error = rc_getstringptr(rcp, section, sect_id, key, &value);
327         if (error)
328                 return (error);
329         if (strlen(value) >= maxlen) {
330                 fprintf(stderr, "line too long for key '%s' in section '%s',"
331                     "max = %d\n",key, section, maxlen);
332                 return (EINVAL);
333         }
334         strcpy(dest,value);
335         return (0);
336 }
337
338 int
339 rc_getint(struct rcfile *rcp, const char *section, int sect_id,
340     const char *key, int *value)
341 {
342         struct rcsection *rsp;
343         struct rckey *rkp;
344
345         rsp = rc_findsect(rcp, section, sect_id);
346         if (!rsp)
347                 return (ENOENT);
348         rkp = rc_sect_findkey(rsp,key);
349         if (!rkp)
350                 return (ENOENT);
351         errno = 0;
352         *value = strtol(rkp->rk_value,NULL,0);
353         if (errno) {
354                 fprintf(stderr, "invalid int value '%s' for key '%s' in "
355                     "section '%s'\n",rkp->rk_value,key,section);
356                 return (errno);
357         }
358         return (0);
359 }
360
361 /*
362  * 1,yes,true
363  * 0,no,false
364  */
365 int
366 rc_getbool(struct rcfile *rcp, const char *section, int sect_id,
367     const char *key, int *value)
368 {
369         struct rcsection *rsp;
370         struct rckey *rkp;
371         char *p;
372
373         rsp = rc_findsect(rcp, section, sect_id);
374         if (!rsp)
375                 return (ENOENT);
376         rkp = rc_sect_findkey(rsp,key);
377         if (!rkp)
378                 return (ENOENT);
379         p = rkp->rk_value;
380         while (*p && isspace(*p)) p++;
381         if (*p == '0' || strcasecmp(p,"no") == 0 ||
382             strcasecmp(p, "false") == 0 ||
383             strcasecmp(p, "off") == 0) {
384                 *value = 0;
385                 return (0);
386         }
387         if (*p == '1' || strcasecmp(p,"yes") == 0 ||
388             strcasecmp(p, "true") == 0 ||
389             strcasecmp(p, "on") == 0) {
390                 *value = 1;
391                 return (0);
392         }
393         fprintf(stderr, "invalid boolean value '%s' for key '%s' in section "
394             "'%s' \n",p, key, section);
395         return (EINVAL);
396 }
397
398 /* Count how many sections with given name exists in configuration. */
399 int rc_getsectionscount(struct rcfile *f, const char *sectname)
400 {
401         struct rcsection *p;
402         int count = 0;
403
404         p = rc_findsect(f, sectname, 0);
405         if (p) {
406                 while (p != NULL) {
407                         count = p->rs_id + 1;
408                         p = rc_findsect(f, sectname, count);
409                 }
410                 return (count);
411         } else
412                 return (0);
413 }
414
415 char **
416 rc_getkeys(struct rcfile *rcp, const char *sectname, int sect_id)
417 {
418         struct rcsection *rsp;
419         struct rckey *p;
420         char **names_tbl;
421         int i = 0, count = 0;
422
423         rsp = rc_findsect(rcp, sectname, sect_id);
424         if (rsp == NULL)
425                 return (NULL);
426
427         SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
428                 count++;
429
430         names_tbl = malloc(sizeof(char *) * (count + 1));
431         if (names_tbl == NULL)
432                 return (NULL);
433
434         SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
435                 names_tbl[i++] = p->rk_name;
436
437         names_tbl[i] = NULL;
438         return (names_tbl);
439 }
440