1
/*
2
 *  The Mana World
3
 *  Copyright (C) 2004  The Mana World Development Team
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
#include "configlistener.h"
23
#include "configuration.h"
24
#include "log.h"
25
26
#include "utils/stringutils.h"
27
#include "utils/xml.h"
28
29
void ConfigurationObject::setValue(const std::string &key,
30
                                   const std::string &value)
31
{
32
    mOptions[key] = value;
33
}
34
35
void Configuration::setValue(const std::string &key, const std::string &value)
36
{
37
    ConfigurationObject::setValue(key, value);
38
39
    // Notify listeners
40
    ListenerMapIterator list = mListenerMap.find(key);
41
    if (list != mListenerMap.end()) {
42
        Listeners listeners = list->second;
43
        for (ListenerIterator i = listeners.begin(); i != listeners.end(); i++)
44
        {
45
            (*i)->optionChanged(key);
46
        }
47
    }
48
}
49
50
std::string ConfigurationObject::getValue(const std::string &key,
51
                                          const std::string &deflt) const
52
{
53
    Options::const_iterator iter = mOptions.find(key);
54
    return ((iter != mOptions.end()) ? iter->second : deflt);
55
}
56
57
int ConfigurationObject::getValue(const std::string &key, int deflt) const
58
{
59
    Options::const_iterator iter = mOptions.find(key);
60
    return (iter != mOptions.end()) ? atoi(iter->second.c_str()) : deflt;
61
}
62
63
unsigned ConfigurationObject::getValue(const std::string &key,
64
                                       unsigned deflt) const
65
{
66
    Options::const_iterator iter = mOptions.find(key);
67
    return (iter != mOptions.end()) ? atol(iter->second.c_str()) : deflt;
68
}
69
70
double ConfigurationObject::getValue(const std::string &key,
71
                                     double deflt) const
72
{
73
    Options::const_iterator iter = mOptions.find(key);
74
    return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt;
75
}
76
77
void ConfigurationObject::deleteList(const std::string &name)
78
{
79
    for (ConfigurationList::const_iterator
80
             it = mContainerOptions[name].begin(); it != mContainerOptions[name].end(); it++)
81
        delete *it;
82
83
    mContainerOptions[name].clear();
84
}
85
86
void ConfigurationObject::clear()
87
{
88
    for (std::map<std::string, ConfigurationList>::const_iterator
89
             it = mContainerOptions.begin(); it != mContainerOptions.end(); it++)
90
        deleteList(it->first);
91
    mOptions.clear();
92
}
93
94
ConfigurationObject::~ConfigurationObject()
95
{
96
    clear();
97
}
98
99
void ConfigurationObject::initFromXML(xmlNodePtr parent_node)
100
{
101
    clear();
102
103
    for_each_xml_child_node(node, parent_node)
104
    {
105
        if (xmlStrEqual(node->name, BAD_CAST "list")) {
106
            // list option handling
107
108
            std::string name = XML::getProperty(node, "name", std::string());
109
110
            for_each_xml_child_node(subnode, node)
111
            {
112
                if (xmlStrEqual(subnode->name, BAD_CAST name.c_str())
113
                    && subnode->type == XML_ELEMENT_NODE) {
114
                    ConfigurationObject *cobj = new ConfigurationObject;
115
116
                    cobj->initFromXML(subnode); // recurse
117
118
                    mContainerOptions[name].push_back(cobj);
119
                }
120
            }
121
122
        } else if (xmlStrEqual(node->name, BAD_CAST "option")) {
123
            // single option handling
124
125
            std::string name = XML::getProperty(node, "name", std::string());
126
            std::string value = XML::getProperty(node, "value", std::string());
127
128
            if (!name.empty() && !value.empty())
129
                mOptions[name] = value;
130
        } // otherwise ignore
131
    }
132
}
133
134
void Configuration::init(const std::string &filename)
135
{
136
    mConfigPath = filename;
137
138
    // Do not attempt to read config from non-existant file
139
    FILE *testFile = fopen(filename.c_str(), "r");
140
    if (!testFile) {
141
        return;
142
    }
143
    else {
144
        fclose(testFile);
145
    }
146
147
    xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
148
149
    if (!doc) return;
150
151
    xmlNodePtr rootNode = xmlDocGetRootElement(doc);
152
153
    if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "configuration")) {
154
        logger->log("Warning: No configuration file (%s)", filename.c_str());
155
        xmlFreeDoc(doc);
156
        return;
157
    }
158
159
    initFromXML(rootNode);
160
161
    xmlFreeDoc(doc);
162
}
163
164
void ConfigurationObject::writeToXML(xmlTextWriterPtr writer)
165
{
166
    for (Options::const_iterator i = mOptions.begin(), i_end = mOptions.end();
167
         i != i_end; ++i)
168
    {
169
        xmlTextWriterStartElement(writer, BAD_CAST "option");
170
        xmlTextWriterWriteAttribute(writer,
171
                BAD_CAST "name", BAD_CAST i->first.c_str());
172
        xmlTextWriterWriteAttribute(writer,
173
                BAD_CAST "value", BAD_CAST i->second.c_str());
174
        xmlTextWriterEndElement(writer);
175
    }
176
177
    for (std::map<std::string, ConfigurationList>::const_iterator
178
             it = mContainerOptions.begin(); it != mContainerOptions.end(); it++) {
179
        const char *name = it->first.c_str();
180
181
        xmlTextWriterStartElement(writer, BAD_CAST "list");
182
        xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name);
183
184
        // recurse on all elements
185
        for (ConfigurationList::const_iterator
186
                 elt_it = it->second.begin(); elt_it != it->second.end(); elt_it++) {
187
188
            xmlTextWriterStartElement(writer, BAD_CAST name);
189
            (*elt_it)->writeToXML(writer);
190
            xmlTextWriterEndElement(writer);
191
        }
192
193
        xmlTextWriterEndElement(writer);
194
    }
195
}
196
197
void Configuration::write()
198
{
199
    // Do not attempt to write to file that cannot be opened for writing
200
    FILE *testFile = fopen(mConfigPath.c_str(), "w");
201
    if (!testFile) {
202
        logger->log("Configuration::write() couldn't open %s for writing",
203
                    mConfigPath.c_str());
204
        return;
205
    }
206
    else {
207
        fclose(testFile);
208
    }
209
210
    xmlTextWriterPtr writer = xmlNewTextWriterFilename(mConfigPath.c_str(), 0);
211
212
    if (!writer) {
213
        logger->log("Configuration::write() error while creating writer");
214
        return;
215
    }
216
217
    logger->log("Configuration::write() writing configuration...");
218
219
    xmlTextWriterSetIndent(writer, 1);
220
    xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
221
    xmlTextWriterStartElement(writer, BAD_CAST "configuration");
222
223
    writeToXML(writer);
224
225
    xmlTextWriterEndDocument(writer);
226
    xmlFreeTextWriter(writer);
227
}
228
229
void Configuration::addListener(
230
        const std::string &key, ConfigListener *listener)
231
{
232
    mListenerMap[key].push_front(listener);
233
}
234
235
void Configuration::removeListener(
236
        const std::string &key, ConfigListener *listener)
237
{
238
    mListenerMap[key].remove(listener);
239
}