1 #pragma once
2 
3 // This module implements a configuration parser. Clients can query the
4 // contents of a configuration file through the interface provided here.
5 // The current implementation is read-only; mutations are only kept in
6 // memory. This parser supports the INI file format.
7 
8 // Implementation notes:
9 // - Key/value pairs that are not within a section are assumed to be under
10 //   the |CONFIG_DEFAULT_SECTION| section.
11 // - Multiple sections with the same name will be merged as if they were in
12 //   a single section.
13 // - Empty sections with no key/value pairs will be treated as if they do
14 //   not exist. In other words, |config_has_section| will return false for
15 //   empty sections.
16 // - Duplicate keys in a section will overwrite previous values.
17 // - All strings are case sensitive.
18 
19 #include <stdbool.h>
20 #include <list>
21 #include <memory>
22 #include <string>
23 
24 // The default section name to use if a key/value pair is not defined within
25 // a section.
26 #define CONFIG_DEFAULT_SECTION "Global"
27 
28 struct entry_t {
29   std::string key;
30   std::string value;
31 };
32 
33 struct section_t {
34   std::string name;
35   std::list<entry_t> entries;
36   void Set(std::string key, std::string value);
37   std::list<entry_t>::iterator Find(const std::string& key);
38   bool Has(const std::string& key);
39 };
40 
41 struct config_t {
42   std::list<section_t> sections;
43   std::list<section_t>::iterator Find(const std::string& section);
44   bool Has(const std::string& section);
45 };
46 
47 // Creates a new config object with no entries (i.e. not backed by a file).
48 // This function returns a unique pointer to config object.
49 std::unique_ptr<config_t> config_new_empty(void);
50 
51 // Loads the specified file and returns a handle to the config file. If there
52 // was a problem loading the file, this function returns
53 // NULL. |filename| must not be NULL and must point to a readable
54 // file on the filesystem.
55 std::unique_ptr<config_t> config_new(const char* filename);
56 
57 // Read the checksum from the |filename|
58 std::string checksum_read(const char* filename);
59 
60 // Clones |src|, including all of it's sections, keys, and values.
61 // Returns a new config which is a copy and separated from the original;
62 // changes to the new config are not reflected in any way in the original.
63 //
64 // This function will not return NULL.
65 std::unique_ptr<config_t> config_new_clone(const config_t& src);
66 
67 // Returns true if the config file contains a section named |section|. If
68 // the section has no key/value pairs in it, this function will return false.
69 bool config_has_section(const config_t& config, const std::string& section);
70 
71 // Returns true if the config file has a key named |key| under |section|.
72 // Returns false otherwise.
73 bool config_has_key(const config_t& config, const std::string& section,
74                     const std::string& key);
75 
76 // Returns the integral value for a given |key| in |section|. If |section|
77 // or |key| do not exist, or the value cannot be fully converted to an integer,
78 // this function returns |def_value|.
79 int config_get_int(const config_t& config, const std::string& section,
80                    const std::string& key, int def_value);
81 
82 // Returns the uint64_t value for a given |key| in |section|. If |section|
83 // or |key| do not exist, or the value cannot be fully converted to an integer,
84 // this function returns |def_value|.
85 uint64_t config_get_uint64(const config_t& config, const std::string& section,
86                            const std::string& key, uint64_t def_value);
87 
88 // Returns the boolean value for a given |key| in |section|. If |section|
89 // or |key| do not exist, or the value cannot be converted to a boolean, this
90 // function returns |def_value|.
91 bool config_get_bool(const config_t& config, const std::string& section,
92                      const std::string& key, bool def_value);
93 
94 // Returns the string value for a given |key| in |section|. If |section| or
95 // |key| do not exist, this function returns |def_value|. The returned string
96 // is owned by the config module and must not be freed or modified. |def_value|
97 // may be NULL.
98 const std::string* config_get_string(const config_t& config,
99                                      const std::string& section,
100                                      const std::string& key,
101                                      const std::string* def_value);
102 
103 // Sets an integral value for the |key| in |section|. If |key| or |section| do
104 // not already exist, this function creates them. |config| must not be NULL.
105 void config_set_int(config_t* config, const std::string& section,
106                     const std::string& key, int value);
107 
108 // Sets a uint64_t value for the |key| in |section|. If |key| or |section| do
109 // not already exist, this function creates them. |config| must not be NULL.
110 void config_set_uint64(config_t* config, const std::string& section,
111                        const std::string& key, uint64_t value);
112 
113 // Sets a boolean value for the |key| in |section|. If |key| or |section| do
114 // not already exist, this function creates them. |config| must not be NULL.
115 void config_set_bool(config_t* config, const std::string& section,
116                      const std::string& key, bool value);
117 
118 // Sets a string value for the |key| in |section|. If |key| or |section| do
119 // not already exist, this function creates them. |config| must not be NULL.
120 void config_set_string(config_t* config, const std::string& section,
121                        const std::string& key, const std::string& value);
122 
123 // Removes |section| from the |config| (and, as a result, all keys in the
124 // section).
125 // Returns true if |section| was found and removed from |config|, false
126 // otherwise.
127 // |config| may be NULL.
128 bool config_remove_section(config_t* config, const std::string& section);
129 
130 // Removes one specific |key| residing in |section| of the |config|. Returns
131 // true
132 // if the section and key were found and the key was removed, false otherwise.
133 // |config|may not be NULL.
134 bool config_remove_key(config_t* config, const std::string& section,
135                        const std::string& key);
136 
137 // Saves |config| to a file given by |filename|. Note that this could be a
138 // destructive operation: if |filename| already exists, it will be overwritten.
139 // The config module does not preserve comments or formatting so if a config
140 // file was opened with |config_new| and subsequently overwritten with
141 // |config_save|, all comments and special formatting in the original file will
142 // be lost. Neither |config| nor |filename| may be NULL.
143 bool config_save(const config_t& config, const std::string& filename);
144 
145 // Saves the encrypted |checksum| of config file to a given |filename| Note
146 // that this could be a destructive operation: if |filename| already exists,
147 // it will be overwritten.
148 bool checksum_save(const std::string& checksum, const std::string& filename);
149