2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @file pluginConfig.hpp
24 * @brief Plugin configuration parser done in C++.
38 #include "pluginConfig.h"
39 #include "pluginConfig.hpp"
41 #define UNUSED(x) (void)(x)
43 ////////////////////////////////////////////////////////////////////////////////
45 ////////////////////////////////////////////////////////////////////////////////
48 * @brief Namespace for all content related to plugin.
54 * @brief Namespace for internal code related to configuration.
59 // trimming functions taken from:
60 // https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
63 * @brief trim from start, i.e. left side
68 static inline std::string <rim(std::string &s)
70 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
71 std::not1(std::ptr_fun<int, int>(std::isspace))));
76 * @brief trim from end, i.e. right side
81 static inline std::string &rtrim(std::string &s)
83 s.erase(std::find_if(s.rbegin(), s.rend(),
84 std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
89 * @brief trim from both ends
94 static inline std::string &trim(std::string &s)
96 return ltrim(rtrim(s));
98 } // end of namespace internal
101 ////////////////////////////////////////////////////////////////////////////////
103 ////////////////////////////////////////////////////////////////////////////////
105 * @brief Namespace for all content related to plugin.
110 * @brief Namespace for internal code related to configuration.
115 * @brief Typedef for configuration key-value map.
118 * |---------------------------|----------------------------------------|
119 * | KEY : char* | VALUE : char* |
120 * |---------------------------|----------------------------------------|
122 * |---------------------------|----------------------------------------|
124 * |---------------------------|----------------------------------------|
126 * |---------------------------|----------------------------------------|
128 typedef std::map<std::string, std::string> MapStrStr;
130 typedef std::pair<std::string, std::string> MapStrStrEntry;
133 * @typedef ListSection
135 * |------------------------------------------|
136 * | SECTION PTR : MapStrStr * |
137 * |------------------------------------------|
139 * |------------------------------------------|
141 * |------------------------------------------|
143 * |------------------------------------------|
145 typedef std::vector<MapStrStr> ListSection;
149 * @brief Typedef for configuration key-value map.
150 * @typedef plugin_internal_MapStrSection
152 * |---------------------------|----------------------------------------|
153 * | SECTION NAME : char* | SECTION PTR : MapStrStr * |
154 * |---------------------------|----------------------------------------|
156 * |---------------------------|----------------------------------------|
158 * |---------------------------|----------------------------------------|
160 * |---------------------------|----------------------------------------|
162 typedef std::map<std::string, MapStrStr *> MapStrSection;
164 typedef std::pair<std::string, MapStrStr *> MapStrSectionEntry;
166 } // end of namespace internal
167 } // end of namespace plugin
169 ////////////////////////////////////////////////////////////////////////////////
170 // ConfigParserState class
171 ////////////////////////////////////////////////////////////////////////////////
174 * @brief Namespace for all content related to plugin.
179 * @brief Namespace for internal code related to configuration.
184 * @brief For storing state of the parser between running line-parsing functions.
186 class ConfigParserState
189 std::string current_section_name;
190 MapStrStr *current_section;
192 } // end of namespace internal
193 } // end of namespace plugin
196 * @brief Namespace for all content related to plugin.
201 * @brief Namespace for internal code related to configuration.
205 ////////////////////////////////////////////////////////////////////////
207 * @brief Internal backing storage for configuration.
209 * Getters and assignment operator are thread safe, constructors and destructor are not.
219 * @brief Filepath to the read configuration file.
221 std::string filepath;
224 * @brief Describes layout of the data in the file.
226 PluginConfigType type;
229 * @brief Variable that stores the all sections of configuration,
230 * meant to be accessed through the field 'configuration'.
232 ListSection sections;
235 * @brief Variable that stores the whole configuration.
237 MapStrSection configuration;
241 : data_mutex(new GMutex), filepath()
243 g_mutex_init(data_mutex);
247 * @brief Loads configuration from the specified file.
249 * @param filepath a path to the configuration file
250 * @param type expected type of configuration file, this value
251 * determines how the file is parsed
253 ConfigData(const std::string &filepath, PluginConfigType type)
254 : data_mutex(new GMutex), filepath(filepath), type(type)
256 g_mutex_init(data_mutex);
257 sections.reserve(128);
258 std::ifstream in(filepath);
259 ConfigParserState state;
264 std::getline(in, line);
266 if (line.length() == 0)
271 case PluginConfigType::CCT_INI:
272 parseLineIni(state, line);
274 case PluginConfigType::CCT_GIT:
275 parseLineGit(state, line);
277 case PluginConfigType::CCT_CSV_COMMA:
278 parseLineCsv(state, line, ',');
280 case PluginConfigType::CCT_CSV_TAB:
281 parseLineCsv(state, line, '\t');
283 case PluginConfigType::CCT_CSV_COLON:
284 parseLineCsv(state, line, ':');
286 case PluginConfigType::CCT_CSV_SEMICOLON:
287 parseLineCsv(state, line, ';');
297 std::cout << "* configuration file " << filepath << " was _loaded" << std::endl;
304 * @brief Copy constructor.
308 ConfigData(const plugin::internal::ConfigData &source)
309 : data_mutex(new GMutex), filepath(), type(), sections(), configuration()
311 g_mutex_init(data_mutex);
312 g_mutex_lock(source.data_mutex);
313 filepath = source.filepath;
315 sections = source.sections;
317 for (auto it = source.configuration.begin(); it != source.configuration.end(); ++it)
322 for (auto sit = source.sections.begin(); sit != source.sections.end(); ++sit, ++index)
323 if (it->second == &(*sit))
332 configuration[it->first] = &(sections.data()[index]);
335 g_mutex_unlock(source.data_mutex);
339 * @brief Assignment operator.
342 * @return :internal::ConfigData&
344 plugin::internal::ConfigData &operator=(const plugin::internal::ConfigData &source)
351 g_mutex_lock(data_mutex);
352 g_mutex_lock(source.data_mutex);
356 g_mutex_lock(source.data_mutex);
357 g_mutex_lock(data_mutex);
360 filepath = source.filepath;
362 sections = source.sections;
363 configuration = MapStrSection();
365 for (auto it = source.configuration.begin(); it != source.configuration.end(); ++it)
370 for (auto sit = source.sections.begin(); sit != source.sections.end(); ++sit, ++index)
371 if (it->second == &(*sit))
380 configuration[it->first] = &(sections.data()[index]);
385 g_mutex_unlock(source.data_mutex);
386 g_mutex_unlock(data_mutex);
390 g_mutex_unlock(data_mutex);
391 g_mutex_unlock(source.data_mutex);
404 g_mutex_clear(data_mutex);
409 void parseLineIni(ConfigParserState &state, const std::string &line)
416 std::string section_name = line.substr(1, line.length() - 2);
417 sections.push_back(MapStrStr());
418 MapStrStr *section = &(sections[sections.size() - 1]);
419 configuration[section_name] = section;
420 state.current_section_name = section_name;
421 state.current_section = section;
425 size_t pos = line.find('=');
426 std::string key = line.substr(0, pos);
427 std::string value = line.substr(pos + 1);
428 state.current_section->insert(MapStrStrEntry(key, value));
432 void parseLineGit(ConfigParserState &state, const std::string &line)
434 if (line[0] == ';' || line[0] == '#')
439 std::string section_name = line.substr(1, line.length() - 2);
440 sections.push_back(MapStrStr());
441 MapStrStr *section = &(sections[sections.size() - 1]);
442 configuration[section_name] = section;
443 state.current_section_name = section_name;
444 state.current_section = section;
448 size_t pos = line.find(" = ");
449 std::string key = line.substr(0, pos);
450 std::string value = line.substr(pos + 3);
452 state.current_section->insert(MapStrStrEntry(key, value));
456 void parseLineCsv(ConfigParserState &state, const std::string &line, char separator)
459 size_t pos1 = line.find_first_of(separator);
460 size_t pos2 = line.find_last_of(separator);
461 std::string section = line.substr(0, pos1);
462 std::string key = line.substr(pos1 + 1, pos2 - pos1 - 1);
463 std::string value = line.substr(pos2 + 1);
464 auto it = configuration.find(section);
466 if (it == configuration.end())
468 sections.push_back(MapStrStr());
469 configuration[section] = &(sections[sections.size() - 1]);
470 configuration[section]->insert(MapStrStrEntry(key, value));
473 it->second->insert(MapStrStrEntry(key, value));
477 * @brief Removes configuration from memory, rendering this configuration invalid.
483 filepath = std::string();
484 //for(auto it = configuration.begin(); it != configuration.end(), ++it)
486 type = PluginConfigType::CCT_INVALID;
487 configuration.clear();
492 inline bool hasSection(const std::string §ion) const
494 g_mutex_lock(data_mutex);
495 bool result = configuration.find(section) != configuration.end();
496 g_mutex_unlock(data_mutex);
502 * @brief This method assumes that the given section exists. Use hasSection()
503 * first, or use hasSectionAndKey() instead.
505 * @param section name of the configuration section
506 * @param key name of the key within that section
507 * @return bool true if such key exists
509 inline bool hasKey(const std::string §ion, const std::string &key) const
511 g_mutex_lock(data_mutex);
512 bool result = configuration.at(section)->find(key) != configuration.at(section)->end();
513 g_mutex_unlock(data_mutex);
517 inline bool hasSectionAndKey(const std::string §ion, const std::string &key) const
519 g_mutex_lock(data_mutex);
520 bool result = configuration.find(section) != configuration.end()
521 && configuration.at(section)->find(key) != configuration.at(section)->end();
522 g_mutex_unlock(data_mutex);
526 inline const std::string &getFilepath() const
528 g_mutex_lock(data_mutex);
529 const std::string &result = filepath;
530 g_mutex_unlock(data_mutex);
534 inline PluginConfigType getType() const
536 g_mutex_lock(data_mutex);
537 PluginConfigType result = type;
538 g_mutex_unlock(data_mutex);
543 //inline const MapStrStr& get_section(const std::string& section) const;
545 inline const std::string &getEntry(const std::string §ion, const std::string &key) const
547 g_mutex_lock(data_mutex);
548 const std::string &result = configuration.at(section)->at(key);
549 g_mutex_unlock(data_mutex);
554 friend std::ostream &operator<<(std::ostream &out, const ConfigData &configuration)
556 out << "sections: " << configuration.configuration.size() << std::endl;
558 for (auto it = configuration.configuration.begin(); it != configuration.configuration.end(); ++it)
560 out << "'" << it->first << "'" << std::endl;
563 #include <features.h>
564 #if __GNUC_PREREQ(4,7)
566 // If gcc_version >= 4.7
567 if (it->second == nullptr)
571 if (it->second == NULL)
577 if (it->second == NULL)
580 out << " nullptr!" << std::endl;
584 out << " entries: " << it->second->size() << std::endl;
586 for (auto sit = it->second->begin(); sit != it->second->end(); ++sit)
587 out << " '" << sit->first << "' -> '" << sit->second << "'" << std::endl;
594 }; // end of class ConfigData
595 } // end of namespace internal
596 } // end of namespace plugin
598 ////////////////////////////////////////////////////////////////////////////////
599 // C++ API implementation
600 ////////////////////////////////////////////////////////////////////////////////
603 * @brief Namespace for all content related to plugin.
610 _configuration = NULL;
615 if (_configuration != NULL)
617 delete _configuration;
618 _configuration = NULL;
622 std::string Config::_getRaw(const std::string §ion, const std::string &key)
624 if (NULL == _configuration)
626 return std::string();
629 if (!_configuration->hasSectionAndKey(section, key))
630 return std::string();
632 return _configuration->getEntry(section, key);
635 const std::string *Config::_getRawPtr(const std::string §ion, const std::string &key)
637 if (NULL == _configuration)
642 if (!_configuration->hasSectionAndKey(section, key))
645 return &(_configuration->getEntry(section, key));
648 bool Config::load(const std::string &filepath, PluginConfigType type)
650 if (NULL != _configuration)
652 delete _configuration;
653 _configuration = NULL;
656 if (filepath.length() > 0)
658 _configuration = new internal::ConfigData(filepath, type);
666 void Config::unload()
668 if (NULL != _configuration)
670 delete _configuration;
671 _configuration = NULL;
676 std::string Config::getString(const std::string §ion, const std::string &key)
678 return _getRaw(section, key);
681 const std::string *Config::getStringPtr(const std::string §ion, const std::string &key)
683 return _getRawPtr(section, key);
686 int Config::getInt(const std::string §ion, const std::string &key)
688 return std::atoi(_getRaw(section, key).c_str());
691 double Config::getDouble(const std::string §ion, const std::string &key)
693 return std::atof(_getRaw(section, key).c_str());
696 bool Config::isLoaded()
701 } // end of namespace plugin
703 ////////////////////////////////////////////////////////////////////////////////
704 // C API implementation
705 ////////////////////////////////////////////////////////////////////////////////
711 ConfigHandle plugin_config_create()
713 return reinterpret_cast<ConfigHandle>(new plugin::Config());
716 void plugin_config_delete(ConfigHandle config_handle)
718 delete reinterpret_cast<plugin::Config *>(config_handle);
721 void plugin_config_load(ConfigHandle config_handle, const char *filepath,
722 PluginConfigType type)
726 plugin::Config *pConfig = reinterpret_cast<plugin::Config *>(config_handle);
727 pConfig->load(filepath, type);
731 void plugin_config_unload(ConfigHandle config_handle)
735 plugin::Config *pConfig =
736 reinterpret_cast<plugin::Config *>(config_handle);
741 const char *plugin_config_get_string(ConfigHandle config_handle,
742 const char *section, const char *key)
746 plugin::Config *pConfig = reinterpret_cast<plugin::Config *>(config_handle);
748 const std::string *val = pConfig->getStringPtr(section, key);
756 int plugin_config_get_int(ConfigHandle config_handle, const char *section, const char *key)
760 plugin::Config *pConfig = reinterpret_cast<plugin::Config *>(config_handle);
762 return pConfig->getInt(section, key);
768 double plugin_config_get_double(ConfigHandle config_handle, const char *section, const char *key)
772 plugin::Config *pConfig = reinterpret_cast<plugin::Config *>(config_handle);
774 return pConfig->getDouble(section, key);
780 bool plugin_config_is_loaded(ConfigHandle config_handle)
784 plugin::Config *pConfig = reinterpret_cast<plugin::Config *>(config_handle);
786 return pConfig->isLoaded();