syndilights/open-lighting-architecture/ola-0.8.4/olad/Preferences.cpp

399 lines
9.0 KiB
C++

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Preferences.cpp
* This class stores preferences in files
* Copyright (C) 2005-2008 Simon Newton
*/
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <fstream>
#include <list>
#include <map>
#include <string>
#include <vector>
#include "ola/Logging.h"
#include "ola/StringUtils.h"
#include "olad/Preferences.h"
namespace ola {
using std::ifstream;
using std::ofstream;
using std::pair;
const char BoolValidator::TRUE[] = "true";
const char BoolValidator::FALSE[] = "false";
const char FileBackedPreferences::OLA_CONFIG_DIR[] = ".ola";
const char FileBackedPreferences::OLA_CONFIG_PREFIX[] = "ola-";
const char FileBackedPreferences::OLA_CONFIG_SUFFIX[] = ".conf";
// Validators
//-----------------------------------------------------------------------------
bool StringValidator::IsValid(const string &value) const {
return !value.empty();
}
bool BoolValidator::IsValid(const string &value) const {
return (value == TRUE || value == FALSE);
}
bool IntValidator::IsValid(const string &value) const {
unsigned int output;
if (!StringToUInt(value, &output))
return false;
return (output >= m_gt && output <= m_lt);
}
bool SetValidator::IsValid(const string &value) const {
return m_values.end() != m_values.find(value);
}
bool IPv4Validator::IsValid(const string &value) const {
if (value.empty())
return m_empty_ok;
vector<string> tokens;
StringSplit(value, tokens, ".");
if (tokens.size() != 4)
return false;
for (unsigned int i = 0 ; i < 4; i++) {
unsigned int octet;
if (!StringToUInt(tokens[i], &octet))
return false;
if (octet > 255)
return false;
}
return true;
}
// Prefs Factory
//-----------------------------------------------------------------------------
/**
* Cleanup
*/
PreferencesFactory::~PreferencesFactory() {
map<string, Preferences*>::const_iterator iter;
for (iter = m_preferences_map.begin(); iter != m_preferences_map.end();
++iter) {
delete iter->second;
}
m_preferences_map.clear();
}
/**
* Lookup a preference object
*/
Preferences *PreferencesFactory::NewPreference(const string &name) {
map<string, Preferences*>::iterator iter = m_preferences_map.find(name);
if (iter == m_preferences_map.end()) {
Preferences *pref = Create(name);
m_preferences_map.insert(pair<string, Preferences*>(name, pref));
return pref;
} else {
return iter->second;
}
}
// Memory Preferences
//-----------------------------------------------------------------------------
/*
* Destroy this object
*/
MemoryPreferences::~MemoryPreferences() {
m_pref_map.clear();
}
/*
* Clear the preferences
*/
void MemoryPreferences::Clear() {
m_pref_map.clear();
}
/*
* Set a preference value, overiding the existing value.
* @param key
* @param value
*/
void MemoryPreferences::SetValue(const string &key, const string &value) {
m_pref_map.erase(key);
m_pref_map.insert(pair<string, string>(key, value));
}
/*
* Adds this preference value to the store
* @param key
* @param value
*/
void MemoryPreferences::SetMultipleValue(const string &key,
const string &value) {
m_pref_map.insert(pair<string, string>(key, value));
}
/*
* Set a preference value only if it doesn't pass the validator.
* Note this only checks the first value.
* @param key
* @param validator A Validator object
* @param value the new value
* @return true if we set the value, false if it already existed
*/
bool MemoryPreferences::SetDefaultValue(const string &key,
const Validator &validator,
const string &value) {
map<string, string>::const_iterator iter;
iter = m_pref_map.find(key);
if (iter == m_pref_map.end() || !validator.IsValid(iter->second)) {
SetValue(key, value);
return true;
}
return false;
}
/*
* Get a preference value
* @param key the key to fetch
* @return the value corrosponding to key, or the empty string if the key
* doesn't exist.
*/
string MemoryPreferences::GetValue(const string &key) const {
map<string, string>::const_iterator iter;
iter = m_pref_map.find(key);
if (iter != m_pref_map.end())
return iter->second;
return "";
}
/*
* Returns all preference values corrosponding to this key
* @returns a vector of strings.
*/
vector<string> MemoryPreferences::GetMultipleValue(const string &key) const {
vector<string> values;
map<string, string>::const_iterator iter;
for (iter = m_pref_map.find(key);
iter != m_pref_map.end() && iter->first == key; ++iter) {
values.push_back(iter->second);
}
return values;
}
/*
* Remove a preference value.
* @param key
*/
void MemoryPreferences::RemoveValue(const string &key) {
m_pref_map.erase(key);
}
/*
* Set a value as a bool.
* @param key
* @param value
*/
void MemoryPreferences::SetValueAsBool(const string &key, bool value) {
m_pref_map.erase(key);
if (value)
m_pref_map.insert(pair<string, string>(key, BoolValidator::TRUE));
else
m_pref_map.insert(pair<string, string>(key, BoolValidator::FALSE));
}
/*
* Get a preference value as a bool
* @param key the key to fetch
* @return true if the value is 'true' or false otherwise
*/
bool MemoryPreferences::GetValueAsBool(const string &key) const {
map<string, string>::const_iterator iter;
iter = m_pref_map.find(key);
if (iter != m_pref_map.end())
return iter->second == BoolValidator::TRUE;
return false;
}
// FileBackedPreferences
//-----------------------------------------------------------------------------
/*
* Load the preferences from storage
*/
bool FileBackedPreferences::Load() {
if (!ChangeDir())
return false;
return LoadFromFile(FileName());
}
/*
* Save the preferences to storage
*/
bool FileBackedPreferences::Save() const {
if (!ChangeDir())
return false;
return SaveToFile(FileName());
}
/*
* Return the name of the file used to save the preferences
*/
const string FileBackedPreferences::FileName() const {
return OLA_CONFIG_PREFIX + m_preference_name + OLA_CONFIG_SUFFIX;
}
/*
* Load these preferences from a file
* @param filename the filename to load from
*/
bool FileBackedPreferences::LoadFromFile(const string &filename) {
ifstream pref_file(filename.data());
if (!pref_file.is_open()) {
OLA_INFO << "Missing " << filename << ": " << strerror(errno) <<
" - this isn't an error, we'll just use the defaults";
return false;
}
m_pref_map.clear();
string line;
while (getline(pref_file, line)) {
StringTrim(&line);
if (line.empty() || line.at(0) == '#')
continue;
vector<string> tokens;
StringSplit(line, tokens, "=");
if (tokens.size() != 2) {
OLA_INFO << "Skipping line: " << line;
continue;
}
string key = tokens[0];
string value = tokens[1];
StringTrim(&key);
StringTrim(&value);
m_pref_map.insert(pair<string, string>(key, value));
}
pref_file.close();
return true;
}
/*
* Save the preferences to a file
* @param filename - the name of the file to save to
*/
bool FileBackedPreferences::SaveToFile(const string &filename) const {
map<string, string>::const_iterator iter;
ofstream pref_file(filename.data());
if (!pref_file.is_open()) {
OLA_INFO << "Missing " << filename << ": " << strerror(errno);
return false;
}
for (iter = m_pref_map.begin(); iter != m_pref_map.end(); ++iter) {
pref_file << iter->first << " = " << iter->second << std::endl;
}
pref_file.close();
return true;
}
/*
* Change to the ola preferences directory
*/
bool FileBackedPreferences::ChangeDir() const {
struct passwd pwd, *pwd_ptr;
unsigned int size = 1024;
bool ok = false;
char *buffer;
while (!ok) {
buffer = new char[size];
int ret = getpwuid_r(getuid(), &pwd, buffer, size, &pwd_ptr);
switch (ret) {
case 0:
ok = true;
break;
case ERANGE:
delete[] buffer;
size += 1024;
break;
default:
delete[] buffer;
return false;
}
}
string home_dir = pwd_ptr->pw_dir;
delete[] buffer;
if (chdir(home_dir.data()))
return false;
if (chdir(OLA_CONFIG_DIR)) {
// try and create it
if (mkdir(OLA_CONFIG_DIR, 0755))
return false;
if (chdir(OLA_CONFIG_DIR))
return false;
}
return true;
}
} // ola