config.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file Config.cpp Implementation of Config class. */
00020 
00021 #include <hn/hnprec.h>
00022 #include <hn/config.h>
00023 #include <hn/log.h>
00024 #include <iostream>
00025 #include <fstream>
00026 
00027 // constructors/destructors
00028 Config::Config() : m_curPath("/") {}
00029 Config::Config(const std::string &filename) : m_curPath("/") {
00030         load(filename);
00031 }
00032 Config::~Config() {}
00033 
00034 /**
00035  * Loads data from configuration file.
00036  */
00037 void Config::load(const std::string &filename) {
00038         CHECK_THROW(filename.size());
00039 
00040         m_configFile = filename;
00041         setPath("/");
00042         std::ifstream ifs(filename.c_str(), std::ios::in);
00043         if (!ifs) {
00044                 logWarning(
00045                         "No config file found, using default configuration "
00046                         "values."
00047                 );
00048                 return;
00049         }
00050 
00051         while (ifs.good()) {
00052                 std::string line;
00053                 std::getline(ifs, line);
00054 
00055                 // Remove preceeding whitespace
00056                 while (*(line.begin()) == ' ') {
00057                         line.erase(line.begin());
00058                 }
00059 
00060                 // Directories
00061                 if ((*(line.begin()) == '[') && (*(--line.end()) == ']')) {
00062                         std::string dir;
00063                         dir += line.substr(1, line.length() - 2);
00064                         setPath("/" + dir);
00065 
00066                         logTrace(TRACE_CONFIG,
00067                                 boost::format("Reading: got path=%s") % dir
00068                         );
00069 
00070                         continue;
00071                 }
00072 
00073                 // Values
00074                 size_t pos = line.find('=', 0);
00075                 if (pos != std::string::npos) {
00076                         std::string name = line.substr(0, pos);
00077                         std::string value = line.substr(pos + 1);
00078                         m_values[m_curPath + name] = value;
00079 
00080                         logTrace(TRACE_CONFIG,
00081                                 boost::format(
00082                                         "Reading: got key=%s "
00083                                         "value=%s curpath=%s"
00084                                 ) % name % value % m_curPath
00085                         );
00086 
00087                         continue;
00088                 }
00089         }
00090         setPath("/");
00091 }
00092 
00093 /**
00094  * Saves data into configuration file.
00095  */
00096 void Config::save(const std::string &filename) const {
00097         CHECK_THROW(filename.size());
00098         std::ofstream ofs(filename.c_str(), std::ios::out);
00099         if (!ofs) {
00100                 logError(
00101                         boost::format("Failed to open config file '%s'"
00102                         " for writing.") % filename
00103                 );
00104                 return;
00105         }
00106 
00107         // root dir values copied here and written separately
00108         std::vector<std::pair<std::string, std::string> > rootValues;
00109 
00110         std::string curpath = "/";
00111         std::string wrpath = "";
00112         for (CIter i = m_values.begin(); i != m_values.end(); ++i) {
00113                 size_t pos = (*i).first.find_last_of('/');
00114                 if (pos == 0) {
00115                         rootValues.push_back(*i);
00116                         continue;
00117                 }
00118                 std::string key = (*i).first.substr(pos + 1);
00119                 std::string path = (*i).first.substr(1, pos > 0 ? pos - 1 :pos);
00120                 std::string value = (*i).second;
00121 
00122                 logTrace(TRACE_CONFIG,
00123                         boost::format("Writing: Key=%s Value=%s Path=%s")
00124                         % key % value % path
00125                 );
00126 
00127                 if (path != wrpath) { // Path not written yet
00128                         ofs << "[" << path << "]\n";
00129                         wrpath = path;
00130                 }
00131                 ofs << key << "=" << value << std::endl;
00132         }
00133 
00134         // root keys are written in section []
00135         ofs << "[]" << std::endl;
00136         while (rootValues.size()) {
00137                 ofs << rootValues.back().first.substr(1) << "=";
00138                 ofs << rootValues.back().second << std::endl;
00139                 rootValues.pop_back();
00140         }
00141 }
00142 
00143 /**
00144  * Changes current active directory.
00145  */
00146 void Config::setPath(const std::string &dir) {
00147         CHECK_THROW(dir.size());
00148 
00149         if (*(dir.begin()) == '/') {
00150                 m_curPath = dir;
00151         } else {
00152                 m_curPath += dir;
00153         }
00154         if (*--m_curPath.end() != '/') {
00155                 m_curPath += '/';
00156         }
00157 }
00158 
00159 void Config::dump() const {
00160         boost::format fmt("[%s]=%s");
00161         for (CIter i = m_values.begin(); i != m_values.end(); ++i) {
00162                 logTrace(TRACE_CONFIG, fmt % (*i).first % (*i).second);
00163         }
00164 }