2 * Trivial smb.conf parsing code
3 * iniparser compatibility layer.
5 * Copyright Jeremy Allison <jra@samba.org> 2014
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, and the entire permission notice in its entirety,
12 * including the disclaimer of warranties.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
20 * ALTERNATIVELY, this product may be distributed under the terms of
21 * the GNU Public License Version 3 or later, in which case the provisions
22 * of the GPL are required INSTEAD OF the above restrictions. (This clause is
23 * necessary due to a potential bad interaction between the GPL and
24 * the restrictions contained in a BSD-style copyright.)
26 * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
36 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 #include "tiniparser.h"
49 struct tiniparser_entry
{
50 struct tiniparser_entry
*next_entry
;
55 struct tiniparser_section
{
56 struct tiniparser_section
*next_section
;
57 struct tiniparser_entry
*entry_list
;
61 struct tiniparser_dictionary
{
62 struct tiniparser_section
*section_list
;
66 * Find a section from a given key.
67 * Also return start of subkey.
68 * Return NULL if section name can't be found,
69 * if no section name given, or no subkey given.
72 static struct tiniparser_section
*find_section(struct tiniparser_dictionary
*d
,
76 struct tiniparser_section
*curr_section
;
89 section_len
= p
- key
;
90 /* Ensure we have at least one character of section name. */
91 if (section_len
== 0) {
94 /* Ensure we have at least one character of subkey. */
99 for (curr_section
= d
->section_list
;
101 curr_section
= curr_section
->next_section
) {
103 * Check if the key section matches the
104 * section name *exactly* (with terminating
105 * null after section_len characters.
107 if ((strncasecmp(key
, curr_section
->section_name
, section_len
) == 0) &&
108 (curr_section
->section_name
[section_len
] == '\0')) {
116 static struct tiniparser_entry
*find_entry(struct tiniparser_section
*section
,
119 struct tiniparser_entry
*curr_entry
;
121 for (curr_entry
= section
->entry_list
;
123 curr_entry
= curr_entry
->next_entry
) {
125 curr_entry
->key
) == 0) {
132 const char *tiniparser_getstring(struct tiniparser_dictionary
*d
,
134 const char *default_value
)
136 struct tiniparser_section
*section
;
137 struct tiniparser_entry
*entry
;
140 section
= find_section(d
, key
, &subkey
);
141 if (section
== NULL
) {
142 return default_value
;
145 entry
= find_entry(section
, subkey
);
147 return default_value
;
154 bool tiniparser_getboolean(struct tiniparser_dictionary
*d
,
158 const char *value
= tiniparser_getstring(d
, key
, NULL
);
161 return default_value
;
181 return default_value
;
184 int tiniparser_getint(struct tiniparser_dictionary
*d
,
188 const char *value
= tiniparser_getstring(d
, key
, NULL
);
191 return default_value
;
194 return (int)strtol(value
, NULL
, 0);
197 static bool value_parser(const char *key
,
201 struct tiniparser_dictionary
*d
=
202 (struct tiniparser_dictionary
*)private_data
;
203 struct tiniparser_section
*section
= d
->section_list
;
204 struct tiniparser_entry
*entry
= NULL
;
208 if (section
== NULL
) {
218 key_len
= strlen(key
) + 1;
219 val_len
= strlen(value
) + 1;
221 entry
= find_entry(section
, key
);
223 /* Replace current value. */
224 char *new_val
= malloc(val_len
);
225 if (new_val
== NULL
) {
228 memcpy(new_val
, value
, val_len
);
230 entry
->value
= new_val
;
234 /* Create a new entry. */
235 entry
= malloc(sizeof(struct tiniparser_entry
));
239 entry
->key
= malloc(key_len
);
240 if (entry
->key
== NULL
) {
244 memcpy(entry
->key
, key
, key_len
);
246 entry
->value
= malloc(val_len
);
247 if (entry
->value
== NULL
) {
252 memcpy(entry
->value
, value
, val_len
);
254 entry
->next_entry
= section
->entry_list
;
255 section
->entry_list
= entry
;
259 static bool section_parser(const char *section_name
,
262 struct tiniparser_section
**pp_section
;
263 struct tiniparser_section
*new_section
;
264 struct tiniparser_dictionary
*d
=
265 (struct tiniparser_dictionary
*)private_data
;
266 size_t section_name_len
;
268 if (section_name
== NULL
) {
272 /* Section names can't contain ':' */
273 if (strchr(section_name
, ':') != NULL
) {
277 /* Do we already have this section ? */
278 for (pp_section
= &d
->section_list
;
280 pp_section
= &(*pp_section
)->next_section
) {
281 if (strcasecmp(section_name
,
282 (*pp_section
)->section_name
) == 0) {
284 * Move to the front of the list for
285 * value_parser() to find it.
288 /* First save current entry. */
289 struct tiniparser_section
*curr_section
= *pp_section
;
291 /* Now unlink current entry from list. */
292 *pp_section
= curr_section
->next_section
;
294 /* Make current entry next point to whole list. */
295 curr_section
->next_section
= d
->section_list
;
297 /* And replace list with current entry at start. */
298 d
->section_list
= curr_section
;
304 section_name_len
= strlen(section_name
) + 1;
306 /* Create new section. */
307 new_section
= malloc(
308 offsetof(struct tiniparser_section
, section_name
) +
310 if (new_section
== NULL
) {
314 memcpy(new_section
->section_name
, section_name
, section_name_len
);
316 new_section
->entry_list
= NULL
;
318 /* Add it to the head of the singly linked list. */
319 new_section
->next_section
= d
->section_list
;
320 d
->section_list
= new_section
;
324 struct tiniparser_dictionary
*tiniparser_load_stream(FILE *fp
)
327 struct tiniparser_dictionary
*d
= NULL
;
329 d
= malloc(sizeof(struct tiniparser_dictionary
));
333 d
->section_list
= NULL
;
341 tiniparser_freedict(d
);
347 struct tiniparser_dictionary
*tiniparser_load(const char *filename
)
349 struct tiniparser_dictionary
*d
;
350 FILE *fp
= fopen(filename
, "r");
356 d
= tiniparser_load_stream(fp
);
363 void tiniparser_freedict(struct tiniparser_dictionary
*d
)
365 struct tiniparser_section
*curr_section
, *next_section
;
371 for (curr_section
= d
->section_list
;
373 curr_section
= next_section
) {
374 struct tiniparser_entry
*curr_entry
, *next_entry
;
376 next_section
= curr_section
->next_section
;
378 for (curr_entry
= curr_section
->entry_list
;
380 curr_entry
= next_entry
) {
381 next_entry
= curr_entry
->next_entry
;
383 free(curr_entry
->key
);
384 free(curr_entry
->value
);