rtems-tools/rtemstoolkit/rld-config.h

279 lines
7.2 KiB
C++

/*
* Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* @file
*
* @ingroup rtems_rld
*
* @brief INI Configuration reader.
*
*/
#if !defined (_RLD_CONFIG_H_)
#define _RLD_CONFIG_H_
#include <string>
#include <list>
#include <vector>
#include <rld.h>
namespace rld
{
namespace config
{
/**
* The configuration item. This is a data component of a record contained
* in a section.
*/
struct item
{
std::string text; /**< The text as read from the configuration. */
/**
* Construct an item.
*/
item (const std::string& text);
item (const char* text);
};
/**
* Configuration item container.
*/
typedef std::vector < item > items;
/**
* Configuration record is a line in a section. There can be multiple
* records with the same key in a section. Keys are specific to a section.
*/
struct record
{
std::string name; //< Name of the record.
items items_; //< The record's items.
/**
* Return true if there is only one item.
*/
bool single () const {
return items_.size () == 1;
}
/**
* Operator to get an item.
*/
const std::string& operator [] (int index) const {
return items_[index].text;
}
};
/**
* Configuration record container.
*/
typedef std::list < record > records;
/**
* Configuration section. A section contains a number of records and the
* records contain [1..n] items.
*/
struct section
{
std::string name; //< Name of the section.
records recs; //< The section's records.
/**
* Has the section got a record ?
*/
bool has_record (const std::string& name) const;
/**
* Find a record and throw an error if not found.
*/
const record& get_record (const std::string& name) const;
/**
* Return the single item in a record. If the record is duplicated an
* error is thrown.
*/
const std::string get_record_item (const std::string& name) const;
/**
* Return the list of items in a record in a strings container.
*/
void get_record_items (const std::string& name, rld::strings& items_) const;
};
/**
* Configuration section container.
*/
typedef std::list < section > sections;
/**
* Container of configuration file paths loaded.
*/
typedef std::vector < std::string > paths;
/**
* The configuration.
*/
class config
{
public:
/**
* Construct an empty configuration.
*/
config(const std::string& search_path = "");
/**
* Desctruct the configuration object.
*/
virtual ~config();
/**
* Set the search path.
*/
void set_search_path (const std::string& search_path);
/**
* Clear the current configuration.
*/
void clear ();
/**
* Load a configuration.
*/
void load (const std::string& name);
/**
* Process any include records in the section named. If the section has
* any records named 'include' split the items and include the
* configuration files.
*/
void includes (const section& sec, bool must_exist = true);
/**
* Get the section and throw an error if not found.
*/
const section& get_section (const std::string& name) const;
/**
* Get the paths of loaded configuration files.
*/
const paths& get_paths () const;
private:
paths search; //< The paths to search for config files in.
paths paths_; //< The path's of the loaded files.
sections secs; //< The sections loaded from configuration files
};
/**
* Return the items from a record.
*/
template < typename T >
void parse_items (const rld::config::record& record,
T& items_,
bool clear = true,
bool split = true)
{
if (clear)
items_.clear ();
for (rld::config::items::const_iterator ii = record.items_.begin ();
ii != record.items_.end ();
++ii)
{
if (split)
{
rld::strings ss;
rld::split (ss, (*ii).text, ',');
std::copy (ss.begin (), ss.end (), std::back_inserter (items_));
}
else
{
items_.push_back ((*ii).text);
}
}
}
/**
* Return the items from a record in a section. Optionally raise an error
* if the record is not found and it is to be present.
*/
template < typename T >
void parse_items (const rld::config::section& section,
const std::string& name,
T& items_,
bool present = false,
bool clear = true,
bool split = true)
{
if (clear)
items_.clear ();
const rld::config::record* rec = 0;
try
{
const rld::config::record& rr = section.get_record (name);
rec = &rr;
}
catch (rld::error re)
{
/*
* Ignore the error if it does not need to exist.
*/
if (present)
throw rld::error ("not found", "record: " + section.name + name);
}
if (rec)
parse_items (*rec, items_, clear, split);
}
/**
* Return the items from a record in a section in the
* configuration. Optionally raise an error if the section is not found and
* it is to be present.
*/
template < typename T >
void parse_items (const rld::config::config& config,
const std::string& section,
const std::string& record,
T& items_,
bool present = false)
{
items_.clear ();
const rld::config::section* sec = 0;
try
{
const rld::config::section& sr = config.get_section (section);
sec = &sr;
}
catch (rld::error re)
{
/*
* Ignore the error if it does not need to exist.
*/
if (present)
throw rld::error ("not found", "section: " + section);
}
if (sec)
parse_items (*sec, record, items_);
}
}
}
#endif