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