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