mirror of
https://git.rtems.org/rtems-tools/
synced 2025-05-14 07:19:34 +08:00
255 lines
5.8 KiB
C++
255 lines
5.8 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.
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include <rld-config.h>
|
|
|
|
#include <SimpleIni.h>
|
|
|
|
namespace rld
|
|
{
|
|
namespace config
|
|
{
|
|
item::item (const std::string& text)
|
|
: text (text)
|
|
{
|
|
}
|
|
|
|
item::item (const char* text)
|
|
: text (text)
|
|
{
|
|
}
|
|
|
|
bool
|
|
section::has_record (const std::string& name) const
|
|
{
|
|
for (records::const_iterator ri = recs.begin ();
|
|
ri != recs.end ();
|
|
++ri)
|
|
{
|
|
if ((*ri).name == name)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const record&
|
|
section::get_record (const std::string& name) const
|
|
{
|
|
for (records::const_iterator ri = recs.begin ();
|
|
ri != recs.end ();
|
|
++ri)
|
|
{
|
|
if ((*ri).name == name)
|
|
return *ri;
|
|
}
|
|
|
|
throw rld::error ("not found", "config record: " + this->name + '/' + name);
|
|
}
|
|
|
|
const std::string
|
|
section::get_record_item (const std::string& rec_name) const
|
|
{
|
|
const record& rec = get_record (rec_name);
|
|
if (rec.items_.size () != 1)
|
|
throw rld::error ("duplicate", "record item: " + name + '/' + rec_name);
|
|
return rec.items_[0].text;
|
|
}
|
|
|
|
void
|
|
section::get_record_items (const std::string& rec_name, rld::strings& items) const
|
|
{
|
|
const record& rec = get_record (rec_name);
|
|
items.clear ();
|
|
for (rld::config::items::const_iterator ii = rec.items_.begin ();
|
|
ii != rec.items_.end ();
|
|
++ii)
|
|
{
|
|
items.push_back ((*ii).text);
|
|
}
|
|
}
|
|
|
|
config::config(const std::string& search_path)
|
|
{
|
|
set_search_path (search_path);
|
|
}
|
|
|
|
config::~config()
|
|
{
|
|
}
|
|
|
|
void
|
|
config::set_search_path (const std::string& search_path)
|
|
{
|
|
if (!search_path.empty ())
|
|
rld::path::path_split (search_path, search);
|
|
}
|
|
|
|
void
|
|
config::clear ()
|
|
{
|
|
secs.clear ();
|
|
}
|
|
|
|
void
|
|
config::load (const std::string& path)
|
|
{
|
|
CSimpleIniCaseA ini (false, true, true);
|
|
|
|
std::string checked_path;
|
|
|
|
if (rld::path::check_file (path))
|
|
{
|
|
checked_path = path;
|
|
}
|
|
else
|
|
{
|
|
bool found = false;
|
|
for (rld::path::paths::const_iterator spi = search.begin ();
|
|
spi != search.end ();
|
|
++spi)
|
|
{
|
|
rld::path::path_join (*spi, path, checked_path);
|
|
if (rld::path::check_file (checked_path))
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
throw rld::error ("Not found.", "load config: " + path);
|
|
}
|
|
|
|
if (ini.LoadFile (checked_path.c_str ()) != SI_OK)
|
|
throw rld::error (::strerror (errno), "load config: " + path);
|
|
|
|
paths_.push_back (checked_path);
|
|
|
|
/*
|
|
* Merge the loaded configuration into our configuration.
|
|
*/
|
|
|
|
CSimpleIniCaseA::TNamesDepend skeys;
|
|
|
|
ini.GetAllSections(skeys);
|
|
|
|
for (CSimpleIniCaseA::TNamesDepend::const_iterator si = skeys.begin ();
|
|
si != skeys.end ();
|
|
++si)
|
|
{
|
|
section sec;
|
|
|
|
sec.name = (*si).pItem;
|
|
|
|
CSimpleIniCaseA::TNamesDepend rkeys;
|
|
|
|
ini.GetAllKeys((*si).pItem, rkeys);
|
|
|
|
for (CSimpleIniCaseA::TNamesDepend::const_iterator ri = rkeys.begin ();
|
|
ri != rkeys.end ();
|
|
++ri)
|
|
{
|
|
record rec;
|
|
|
|
rec.name = (*ri).pItem;
|
|
|
|
CSimpleIniCaseA::TNamesDepend vals;
|
|
|
|
ini.GetAllValues((*si).pItem, (*ri).pItem, vals);
|
|
|
|
for (CSimpleIniCaseA::TNamesDepend::const_iterator vi = vals.begin ();
|
|
vi != vals.end ();
|
|
++vi)
|
|
{
|
|
rec.items_.push_back (item ((*vi).pItem));
|
|
}
|
|
|
|
sec.recs.push_back (rec);
|
|
}
|
|
|
|
secs.push_back (sec);
|
|
|
|
if (sec.name == "includes")
|
|
includes(sec);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
config::includes (const section& sec, bool must_exist)
|
|
{
|
|
bool have_includes = false;
|
|
|
|
try
|
|
{
|
|
rld::strings is;
|
|
parse_items (sec, "include", is);
|
|
|
|
have_includes = true;
|
|
|
|
/*
|
|
* Include records are a paths which we can load.
|
|
*/
|
|
|
|
for (rld::strings::const_iterator isi = is.begin ();
|
|
isi != is.end ();
|
|
++isi)
|
|
{
|
|
load (*isi);
|
|
}
|
|
}
|
|
catch (rld::error re)
|
|
{
|
|
/*
|
|
* No include records, must be all inlined. If we have includes it must
|
|
* be another error so throw it.
|
|
*/
|
|
if (have_includes || (!have_includes && must_exist))
|
|
throw;
|
|
}
|
|
}
|
|
|
|
const section&
|
|
config::get_section (const std::string& name) const
|
|
{
|
|
for (sections::const_iterator si = secs.begin ();
|
|
si != secs.end ();
|
|
++si)
|
|
{
|
|
if ((*si).name == name)
|
|
return *si;
|
|
}
|
|
|
|
throw error ("not found", "config section: " + name);
|
|
}
|
|
|
|
const paths&
|
|
config::get_paths () const
|
|
{
|
|
return paths_;
|
|
}
|
|
}
|
|
}
|