1d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#pragma once
2d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
3d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// This module implements a configuration parser. Clients can query the
4d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// contents of a configuration file through the interface provided here.
5d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// The current implementation is read-only; mutations are only kept in
6d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// memory. This parser supports the INI file format.
7d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
8d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Implementation notes:
9d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// - Key/value pairs that are not within a section are assumed to be under
10d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati//   the |CONFIG_DEFAULT_SECTION| section.
11d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// - Multiple sections with the same name will be merged as if they were in
12d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati//   a single section.
13d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// - Empty sections with no key/value pairs will be treated as if they do
14d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati//   not exist. In other words, |config_has_section| will return false for
15d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati//   empty sections.
16d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// - Duplicate keys in a section will overwrite previous values.
1736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// - All strings are case sensitive.
18d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
19d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#include <stdbool.h>
20d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
21d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// The default section name to use if a key/value pair is not defined within
22d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// a section.
23d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati#define CONFIG_DEFAULT_SECTION "Global"
24d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
25d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatitypedef struct config_t config_t;
2636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatitypedef struct config_section_node_t config_section_node_t;
27d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
287f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati// Creates a new config object with no entries (i.e. not backed by a file).
297f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati// This function returns a config object or NULL on error. Clients must call
307f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati// |config_free| on the returned handle when it is no longer required.
317f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavaticonfig_t *config_new_empty(void);
327f280eb2f5f674e0329e21e0babe459a8b205b3fSharvil Nanavati
33d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Loads the specified file and returns a handle to the config file. If there
34d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// was a problem loading the file or allocating memory, this function returns
35d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// NULL. Clients must call |config_free| on the returned handle when it is no
36d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// longer required. |filename| must not be NULL and must point to a readable
37d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// file on the filesystem.
38d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavaticonfig_t *config_new(const char *filename);
39d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
40d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Frees resources associated with the config file. No further operations may
41d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// be performed on the |config| object after calling this function. |config|
42d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// may be NULL.
43d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_free(config_t *config);
44d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
45d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns true if the config file contains a section named |section|. If
46d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// the section has no key/value pairs in it, this function will return false.
47d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// |config| and |section| must not be NULL.
48d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_has_section(const config_t *config, const char *section);
49d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
50d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns true if the config file has a key named |key| under |section|.
51d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns false otherwise. |config|, |section|, and |key| must not be NULL.
52d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_has_key(const config_t *config, const char *section, const char *key);
53d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
54d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns the integral value for a given |key| in |section|. If |section|
55d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// or |key| do not exist, or the value cannot be fully converted to an integer,
56d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// this function returns |def_value|. |config|, |section|, and |key| must not
57d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// be NULL.
58d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatiint config_get_int(const config_t *config, const char *section, const char *key, int def_value);
59d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
60d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns the boolean value for a given |key| in |section|. If |section|
61d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// or |key| do not exist, or the value cannot be converted to a boolean, this
62d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// function returns |def_value|. |config|, |section|, and |key| must not be NULL.
63d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavatibool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value);
64d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
65d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Returns the string value for a given |key| in |section|. If |section| or
66d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// |key| do not exist, this function returns |def_value|. The returned string
67d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// is owned by the config module and must not be freed. |config|, |section|,
68d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// and |key| must not be NULL. |def_value| may be NULL.
69d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavaticonst char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value);
70d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
71d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Sets an integral value for the |key| in |section|. If |key| or |section| do
72d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// not already exist, this function creates them. |config|, |section|, and |key|
73d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// must not be NULL.
74d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_int(config_t *config, const char *section, const char *key, int value);
75d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
76d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Sets a boolean value for the |key| in |section|. If |key| or |section| do
77d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// not already exist, this function creates them. |config|, |section|, and |key|
78d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// must not be NULL.
79d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_bool(config_t *config, const char *section, const char *key, bool value);
80d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati
81d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// Sets a string value for the |key| in |section|. If |key| or |section| do
82d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// not already exist, this function creates them. |config|, |section|, |key|, and
83d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavati// |value| must not be NULL.
84d1c453f4f9648bb5eef80df106e79e3f916f301cSharvil Nanavativoid config_set_string(config_t *config, const char *section, const char *key, const char *value);
8536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
8636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Removes |section| from the |config| (and, as a result, all keys in the section).
8736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Returns true if |section| was found and removed from |config|, false otherwise.
8836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Neither |config| nor |section| may be NULL.
8936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_remove_section(config_t *config, const char *section);
9036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
9136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Removes one specific |key| residing in |section| of the |config|. Returns true
9236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// if the section and key were found and the key was removed, false otherwise.
9336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// None of |config|, |section|, or |key| may be NULL.
9436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_remove_key(config_t *config, const char *section, const char *key);
9536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
9636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Returns an iterator to the first section in the config file. If there are no
9736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// sections, the iterator will equal the return value of |config_section_end|.
9836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// The returned pointer must be treated as an opaque handle and must not be freed.
9936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// The iterator is invalidated on any config mutating operation. |config| may not
10036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// be NULL.
10136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_begin(const config_t *config);
10236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
10336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Returns an iterator to one past the last section in the config file. It does not
10436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// represent a valid section, but can be used to determine if all sections have been
10536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// iterated over. The returned pointer must be treated as an opaque handle and must
10636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// not be freed and must not be iterated on (must not call |config_section_next| on
10736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// it). |config| may not be NULL.
10836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_end(const config_t *config);
10936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
11036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Moves |iter| to the next section. If there are no more sections, |iter| will
11136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// equal the value of |config_section_end|. |iter| may not be NULL and must be
11236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// a pointer returned by either |config_section_begin| or |config_section_next|.
11336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst config_section_node_t *config_section_next(const config_section_node_t *iter);
11436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
11536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Returns the name of the section referred to by |iter|. The returned pointer is
11636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// owned by the config module and must not be freed by the caller. The pointer will
11736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// remain valid until |config_free| is called. |iter| may not be NULL and must not
11836c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// equal the value returned by |config_section_end|.
11936c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavaticonst char *config_section_name(const config_section_node_t *iter);
12036c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati
12136c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// Saves |config| to a file given by |filename|. Note that this could be a destructive
12236c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// operation: if |filename| already exists, it will be overwritten. The config
12336c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// module does not preserve comments or formatting so if a config file was opened
12436c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// with |config_new| and subsequently overwritten with |config_save|, all comments
12536c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// and special formatting in the original file will be lost. Neither |config| nor
12636c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavati// |filename| may be NULL.
12736c1c09593a58717c78497cd55c4ed1dcf52183eSharvil Nanavatibool config_save(const config_t *config, const char *filename);
128