[ea29902] | 1 | /* |
---|
| 2 | * Copyright (c) 2014, Chris Johns <chrisj@rtems.org> |
---|
| 3 | * |
---|
| 4 | * Permission to use, copy, modify, and/or distribute this software for any |
---|
| 5 | * purpose with or without fee is hereby granted, provided that the above |
---|
| 6 | * copyright notice and this permission notice appear in all copies. |
---|
| 7 | * |
---|
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
---|
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
---|
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
| 15 | */ |
---|
| 16 | /** |
---|
| 17 | * @file |
---|
| 18 | * |
---|
| 19 | * @ingroup rtems_rld |
---|
| 20 | * |
---|
| 21 | * @brief INI Configuration reader. |
---|
| 22 | * |
---|
| 23 | */ |
---|
| 24 | |
---|
| 25 | #include <errno.h> |
---|
| 26 | |
---|
| 27 | #include <rld-config.h> |
---|
| 28 | |
---|
| 29 | #include <SimpleIni.h> |
---|
| 30 | |
---|
| 31 | namespace rld |
---|
| 32 | { |
---|
| 33 | namespace config |
---|
| 34 | { |
---|
| 35 | item::item (const std::string& text) |
---|
| 36 | : text (text) |
---|
| 37 | { |
---|
| 38 | } |
---|
| 39 | |
---|
| 40 | item::item (const char* text) |
---|
| 41 | : text (text) |
---|
| 42 | { |
---|
| 43 | } |
---|
| 44 | |
---|
[6fb1409] | 45 | bool |
---|
| 46 | section::has_record (const std::string& name) const |
---|
| 47 | { |
---|
| 48 | for (records::const_iterator ri = recs.begin (); |
---|
| 49 | ri != recs.end (); |
---|
| 50 | ++ri) |
---|
| 51 | { |
---|
| 52 | if ((*ri).name == name) |
---|
| 53 | return true; |
---|
| 54 | } |
---|
| 55 | return false; |
---|
| 56 | } |
---|
| 57 | |
---|
[ea29902] | 58 | const record& |
---|
| 59 | section::get_record (const std::string& name) const |
---|
| 60 | { |
---|
| 61 | for (records::const_iterator ri = recs.begin (); |
---|
| 62 | ri != recs.end (); |
---|
| 63 | ++ri) |
---|
| 64 | { |
---|
| 65 | if ((*ri).name == name) |
---|
| 66 | return *ri; |
---|
| 67 | } |
---|
| 68 | |
---|
[6fb1409] | 69 | throw rld::error ("not found", "config record: " + this->name + '/' + name); |
---|
[ea29902] | 70 | } |
---|
| 71 | |
---|
[6506aa1] | 72 | const std::string |
---|
[058d502] | 73 | section::get_record_item (const std::string& rec_name) const |
---|
| 74 | { |
---|
| 75 | const record& rec = get_record (rec_name); |
---|
[097f1fd] | 76 | if (rec.items_.size () != 1) |
---|
[058d502] | 77 | throw rld::error ("duplicate", "record item: " + name + '/' + rec_name); |
---|
[097f1fd] | 78 | return rec.items_[0].text; |
---|
[058d502] | 79 | } |
---|
| 80 | |
---|
| 81 | void |
---|
| 82 | section::get_record_items (const std::string& rec_name, rld::strings& items) const |
---|
| 83 | { |
---|
| 84 | const record& rec = get_record (rec_name); |
---|
| 85 | items.clear (); |
---|
[097f1fd] | 86 | for (rld::config::items::const_iterator ii = rec.items_.begin (); |
---|
| 87 | ii != rec.items_.end (); |
---|
[058d502] | 88 | ++ii) |
---|
| 89 | { |
---|
| 90 | items.push_back ((*ii).text); |
---|
| 91 | } |
---|
| 92 | } |
---|
| 93 | |
---|
[6506aa1] | 94 | config::config(const std::string& search_path) |
---|
[ea29902] | 95 | { |
---|
[6506aa1] | 96 | set_search_path (search_path); |
---|
[ea29902] | 97 | } |
---|
| 98 | |
---|
| 99 | config::~config() |
---|
| 100 | { |
---|
| 101 | } |
---|
| 102 | |
---|
[6506aa1] | 103 | void |
---|
| 104 | config::set_search_path (const std::string& search_path) |
---|
| 105 | { |
---|
| 106 | if (!search_path.empty ()) |
---|
| 107 | rld::path::path_split (search_path, search); |
---|
| 108 | } |
---|
| 109 | |
---|
[ea29902] | 110 | void |
---|
| 111 | config::clear () |
---|
| 112 | { |
---|
| 113 | secs.clear (); |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | void |
---|
| 117 | config::load (const std::string& path) |
---|
| 118 | { |
---|
| 119 | CSimpleIniCaseA ini (false, true, true); |
---|
| 120 | |
---|
[6506aa1] | 121 | std::string checked_path; |
---|
| 122 | |
---|
| 123 | if (rld::path::check_file (path)) |
---|
| 124 | { |
---|
| 125 | checked_path = path; |
---|
| 126 | } |
---|
| 127 | else |
---|
| 128 | { |
---|
| 129 | bool found = false; |
---|
| 130 | for (rld::path::paths::const_iterator spi = search.begin (); |
---|
| 131 | spi != search.end (); |
---|
| 132 | ++spi) |
---|
| 133 | { |
---|
| 134 | rld::path::path_join (*spi, path, checked_path); |
---|
| 135 | if (rld::path::check_file (checked_path)) |
---|
| 136 | { |
---|
| 137 | found = true; |
---|
| 138 | break; |
---|
| 139 | } |
---|
| 140 | } |
---|
| 141 | if (!found) |
---|
| 142 | throw rld::error ("Not found.", "load config: " + path); |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | if (ini.LoadFile (checked_path.c_str ()) != SI_OK) |
---|
[ea29902] | 146 | throw rld::error (::strerror (errno), "load config: " + path); |
---|
| 147 | |
---|
[6506aa1] | 148 | paths_.push_back (checked_path); |
---|
[ea29902] | 149 | |
---|
| 150 | /* |
---|
| 151 | * Merge the loaded configuration into our configuration. |
---|
| 152 | */ |
---|
| 153 | |
---|
| 154 | CSimpleIniCaseA::TNamesDepend skeys; |
---|
| 155 | |
---|
| 156 | ini.GetAllSections(skeys); |
---|
| 157 | |
---|
| 158 | for (CSimpleIniCaseA::TNamesDepend::const_iterator si = skeys.begin (); |
---|
| 159 | si != skeys.end (); |
---|
| 160 | ++si) |
---|
| 161 | { |
---|
| 162 | section sec; |
---|
| 163 | |
---|
| 164 | sec.name = (*si).pItem; |
---|
| 165 | |
---|
| 166 | CSimpleIniCaseA::TNamesDepend rkeys; |
---|
| 167 | |
---|
| 168 | ini.GetAllKeys((*si).pItem, rkeys); |
---|
| 169 | |
---|
| 170 | for (CSimpleIniCaseA::TNamesDepend::const_iterator ri = rkeys.begin (); |
---|
| 171 | ri != rkeys.end (); |
---|
| 172 | ++ri) |
---|
| 173 | { |
---|
| 174 | record rec; |
---|
| 175 | |
---|
| 176 | rec.name = (*ri).pItem; |
---|
| 177 | |
---|
| 178 | CSimpleIniCaseA::TNamesDepend vals; |
---|
| 179 | |
---|
| 180 | ini.GetAllValues((*si).pItem, (*ri).pItem, vals); |
---|
| 181 | |
---|
| 182 | for (CSimpleIniCaseA::TNamesDepend::const_iterator vi = vals.begin (); |
---|
| 183 | vi != vals.end (); |
---|
| 184 | ++vi) |
---|
| 185 | { |
---|
[097f1fd] | 186 | rec.items_.push_back (item ((*vi).pItem)); |
---|
[ea29902] | 187 | } |
---|
| 188 | |
---|
| 189 | sec.recs.push_back (rec); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | secs.push_back (sec); |
---|
| 193 | } |
---|
| 194 | } |
---|
| 195 | |
---|
[b6d7f5f] | 196 | |
---|
| 197 | void |
---|
| 198 | config::includes (const section& sec, bool must_exist) |
---|
| 199 | { |
---|
| 200 | bool have_includes = false; |
---|
| 201 | |
---|
| 202 | try |
---|
| 203 | { |
---|
[058d502] | 204 | rld::strings is; |
---|
| 205 | parse_items (sec, "include", is); |
---|
[b6d7f5f] | 206 | |
---|
| 207 | have_includes = true; |
---|
| 208 | |
---|
| 209 | /* |
---|
[6506aa1] | 210 | * Include records are a paths which we can load. |
---|
[b6d7f5f] | 211 | */ |
---|
| 212 | |
---|
[058d502] | 213 | for (rld::strings::const_iterator isi = is.begin (); |
---|
| 214 | isi != is.end (); |
---|
| 215 | ++isi) |
---|
[b6d7f5f] | 216 | { |
---|
[058d502] | 217 | load (*isi); |
---|
[b6d7f5f] | 218 | } |
---|
| 219 | } |
---|
| 220 | catch (rld::error re) |
---|
| 221 | { |
---|
| 222 | /* |
---|
| 223 | * No include records, must be all inlined. If we have includes it must |
---|
| 224 | * be another error so throw it. |
---|
| 225 | */ |
---|
| 226 | if (have_includes || (!have_includes && must_exist)) |
---|
| 227 | throw; |
---|
| 228 | } |
---|
| 229 | } |
---|
| 230 | |
---|
[ea29902] | 231 | const section& |
---|
| 232 | config::get_section (const std::string& name) const |
---|
| 233 | { |
---|
| 234 | for (sections::const_iterator si = secs.begin (); |
---|
| 235 | si != secs.end (); |
---|
| 236 | ++si) |
---|
| 237 | { |
---|
| 238 | if ((*si).name == name) |
---|
| 239 | return *si; |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | throw error ("not found", "config section: " + name); |
---|
| 243 | } |
---|
| 244 | |
---|
| 245 | const paths& |
---|
| 246 | config::get_paths () const |
---|
| 247 | { |
---|
[097f1fd] | 248 | return paths_; |
---|
[ea29902] | 249 | } |
---|
| 250 | } |
---|
| 251 | } |
---|