source: nscp/include/settings/settings_old.hpp @ b7d17f8

0.4.00.4.10.4.2
Last change on this file since b7d17f8 was b7d17f8, checked in by Michael Medin <michael@…>, 2 years ago

0.4.x: Major update with a lot of fixes and what not.
Now NSCA is working with old config file as well as a brand new http settings store and many many other fixes.

  • Property mode set to 100644
File size: 15.7 KB
Line 
1#pragma once
2
3#include <iostream>
4#include <fstream>
5#include <string>
6#include <map>
7#include <settings/settings_core.hpp>
8#include <simpleini/SimpleIni.h>
9//#include <settings/macros.h>
10
11#include <strEx.h>
12
13
14//#define MAIN_MODULES_SECTION_OLD _T("modules")
15//#define MAIN_SECTION_TITLE _T("Settings")
16//#define MAIN_STRING_LENGTH _T("string_length")
17
18namespace settings {
19        class OLDSettings : public settings::SettingsInterfaceImpl {
20                std::wstring filename_;
21                typedef std::pair<std::wstring,std::wstring> section_key_type;
22
23                class settings_map : boost::noncopyable {
24                public:
25
26                        typedef std::map<std::wstring,std::wstring> path_map;
27                        typedef std::map<settings_core::key_path_type,settings_core::key_path_type> key_map;
28                        typedef std::pair<std::wstring,std::wstring> section_key_type;
29                        typedef std::pair<settings_core::key_path_type,settings_core::key_path_type> keys_key_type;
30
31                        OLDSettings *parent;
32                        path_map sections_;
33                        key_map keys_;
34
35                        settings_map(OLDSettings *parent) : parent(parent) {}
36
37                        void read_map_file(std::wstring file) {
38                                parent->get_logger()->debug(__FILE__, __LINE__, _T("Reading MAP file: ") + file);
39
40                                std::ifstream in(strEx::wstring_to_string(file).c_str());
41                                if(!in) {
42                                        parent->get_logger()->err(__FILE__, __LINE__, _T("Failed to read MAP file: ") + file);
43                                        return;
44                                }
45                                in.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
46
47                                try{
48                                        std::string tmp;
49                                        while(true) {
50                                                std::getline(in,tmp);
51                                                parse_line(utf8::cvt<std::wstring>(tmp));
52                                        }
53                                }
54                                catch(std::ifstream::failure e){
55                                        if(!in.eof())
56                                                std::cerr << e.what() <<'\n';
57                                }
58                        }
59                        void parse_line(std::wstring line) {
60                                int pos = line.find('#');
61                                if (pos != -1)
62                                        line = line.substr(0, pos);
63                                pos = line.find_first_not_of(_T(" \t"));
64                                if (pos == -1)
65                                        return;
66                                line = line.substr(pos);
67                                pos = line.find('=');
68                                if (pos == -1) {
69                                        parent->get_logger()->err(__FILE__, __LINE__, _T("Invalid syntax: ") + line);
70                                        return;
71                                }
72                                std::pair<std::wstring,std::wstring> old_key = split_key(line.substr(0, pos));
73                                std::pair<std::wstring,std::wstring> new_key = split_key(line.substr(pos+1));
74                                if (old_key.second == _T("*") || old_key.second.empty()) {
75                                        add(line.substr(pos+1), old_key.first);
76                                } else {
77                                        add(new_key.first, new_key.second, old_key.first, old_key.second);
78                                }
79
80                        }
81                        std::pair<std::wstring,std::wstring> split_key(std::wstring key) {
82                                std::pair<std::wstring,std::wstring> ret;
83                                int pos = key.find_last_of('/');
84                                if (pos == -1)
85                                        return std::pair<std::wstring,std::wstring>(key, _T(""));
86                                return std::pair<std::wstring,std::wstring>(key.substr(0, pos), key.substr(pos+1));
87                        }
88
89                        void add(std::wstring path_new, std::wstring path_old) {
90                                sections_[path_new] = path_old;
91                        }
92                        void add(std::wstring path_new, std::wstring key_new, std::wstring path_old, std::wstring key_old) {
93                                settings_core::key_path_type new_key(path_new, key_new);
94                                settings_core::key_path_type old_key(path_old, key_old);
95                                keys_[new_key] = old_key;
96                        }
97                        std::wstring path(std::wstring path_new) {
98                                path_map::iterator it = sections_.find(path_new);
99                                if (it == sections_.end())
100                                        return path_new;
101                                return (*it).second;
102                        }
103                        settings_core::key_path_type key(settings_core::key_path_type new_key) {
104                                key_map::iterator it1 = keys_.find(new_key);
105                                if (it1 != keys_.end()) {
106                                        parent->get_logger()->quick_debug(new_key.first + _T(".") + new_key.second + _T(" not found in alias list"));
107                                        return (*it1).second;
108                                }
109                                path_map::iterator it2 = sections_.find(new_key.first);
110                                if (it2 != sections_.end())
111                                        return settings_core::key_path_type((*it2).second, new_key.second);
112                                return new_key;
113                        }
114
115                        void get_sections(std::wstring path, string_list &list) {
116                                unsigned int path_length = path.length();
117                                BOOST_FOREACH(section_key_type key, sections_) {
118                                        if (path_length == 0 || path == _T("/")) {
119                                                std::wstring::size_type pos = key.first.find(L'/', 1);
120                                                list.push_back(pos == std::wstring::npos?key.first:key.first.substr(0,pos));
121                                        } else if (key.first.length() > path_length && path == key.first.substr(0, path_length)) {
122                                                std::wstring::size_type pos = key.first.find(L'/', path_length+1);
123                                                list.push_back(pos == std::wstring::npos?key.first.substr(path_length+1):key.first.substr(path_length+1,pos-path_length-1));
124                                        }
125                                }
126                                BOOST_FOREACH(keys_key_type key, keys_) {
127                                        if (path.empty() || path == _T("/")) {
128                                                std::wstring::size_type pos = key.first.first.find(L'/', 1);
129                                                if (pos != std::wstring::npos)
130                                                        key.first.first = key.first.first.substr(0,pos);
131                                                list.push_back(key.first.first);
132                                        } else if (key.first.first.length() > path_length && path == key.first.first.substr(0, path_length)) {
133                                                std::wstring::size_type pos = key.first.first.find(L'/', path_length+1);
134                                                list.push_back(pos == std::wstring::npos?key.first.first.substr(path_length+1):key.first.first.substr(path_length+1,pos-path_length-1));
135                                        }
136                                }
137                                list.unique();
138                        }
139
140
141                };
142
143                        settings_map map;
144                        typedef std::map<std::wstring,std::set<std::wstring> > section_cache_type;
145                        section_cache_type section_cache_;
146
147
148                public:
149
150
151                OLDSettings(settings::settings_core *core, std::wstring context) : settings::SettingsInterfaceImpl(core, context), map(this) {
152                        get_logger()->debug(__FILE__, __LINE__, _T("Loading OLD: ") + context);
153                        map.read_map_file(core->find_file(_T("${exe-path}/old-settings.map"), _T("old-settings.map")));
154
155                        string_list list = get_keys(_T("includes"));
156                        BOOST_FOREACH(std::wstring key, list) {
157                                add_child(key);
158                        }
159                }
160                //////////////////////////////////////////////////////////////////////////
161                /// Create a new settings interface of "this kind"
162                ///
163                /// @param context the context to use
164                /// @return the newly created settings interface
165                ///
166                /// @author mickem
167                virtual SettingsInterfaceImpl* create_new_context(std::wstring context) {
168                        return new OLDSettings(get_core(), context);
169                }
170                //////////////////////////////////////////////////////////////////////////
171                /// Get a string value if it does not exist exception will be thrown
172                ///
173                /// @param path the path to look up
174                /// @param key the key to lookup
175                /// @return the string value
176                ///
177                /// @author mickem
178                virtual std::wstring get_real_string(settings_core::key_path_type key) {
179                        key = map.key(key);
180                        return internal_get_value(key.first, key.second);
181                }
182#define UNLIKELY_STRING _T("$$$EMPTY_KEY$$$")
183
184                std::wstring internal_get_value(std::wstring path, std::wstring key, int bufferSize = 1024) {
185                        if (!has_key_int(path, key))
186                                throw KeyNotFoundException(key);
187
188                        TCHAR* buffer = new TCHAR[bufferSize+2];
189                        if (buffer == NULL)
190                                throw settings_exception(_T("Out of memory error!"));
191                        int retVal = GetPrivateProfileString(path.c_str(), key.c_str(), _T(""), buffer, bufferSize, get_file_name().c_str());
192                        if (retVal == bufferSize-1) {
193                                delete [] buffer;
194                                return internal_get_value(path, key, bufferSize*10);
195                        }
196                        std::wstring ret = buffer;
197                        delete [] buffer;
198                        return ret;
199                }
200
201                //////////////////////////////////////////////////////////////////////////
202                /// Get an integer value if it does not exist exception will be thrown
203                ///
204                /// @param path the path to look up
205                /// @param key the key to lookup
206                /// @return the int value
207                ///
208                /// @author mickem
209                virtual int get_real_int(settings_core::key_path_type key) {
210                        std::wstring str = get_real_string(key);
211                        return strEx::stoi(str);
212                }
213                //////////////////////////////////////////////////////////////////////////
214                /// Get a boolean value if it does not exist exception will be thrown
215                ///
216                /// @param path the path to look up
217                /// @param key the key to lookup
218                /// @return the boolean value
219                ///
220                /// @author mickem
221                virtual bool get_real_bool(settings_core::key_path_type key) {
222                        std::wstring str = get_real_string(key);
223                        return SettingsInterfaceImpl::string_to_bool(str);
224                }
225                //////////////////////////////////////////////////////////////////////////
226                /// Check if a key exists
227                ///
228                /// @param path the path to look up
229                /// @param key the key to lookup
230                /// @return true/false if the key exists.
231                ///
232                /// @author mickem
233                virtual bool has_real_key(settings_core::key_path_type key) {
234                        settings_core::key_path_type old = map.key(key);
235                        return has_key_int(old.first, old.second);
236                }
237
238
239                std::set<std::wstring> internal_read_keys_from_section(std::wstring section, int bufferLength = 1024) {
240                        TCHAR* buffer = new TCHAR[bufferLength+1];
241                        if (buffer == NULL)
242                                throw settings_exception(_T("internal_read_keys_from_section:: Failed to allocate memory for buffer!"));
243                        unsigned int count = ::GetPrivateProfileSection(section.c_str(), buffer, bufferLength, get_file_name().c_str());
244                        if (count == bufferLength-2) {
245                                delete [] buffer;
246                                return internal_read_keys_from_section(section, bufferLength*10);
247                        }
248
249                        std::set<std::wstring> ret;
250                        unsigned int last = 0;
251                        for (unsigned int i=0;i<count;i++) {
252                                if (buffer[i] == '\0') {
253                                        std::wstring s = &buffer[last];
254                                        std::size_t p = s.find('=');
255                                        ret.insert((p == std::wstring::npos)?s:s.substr(0,p));
256                                        last = i+1;
257                                }
258                        }
259                        delete [] buffer;
260                        return ret;
261                }
262
263                bool has_key_int(std::wstring path, std::wstring key) {
264                        section_cache_type::const_iterator it = section_cache_.find(path);
265                        if (it == section_cache_.end()) {
266                                std::set<std::wstring> list = internal_read_keys_from_section(path);
267                                section_cache_[path] = list;
268                                it = section_cache_.find(path);
269                        }
270                        return (*it).second.find(key) != (*it).second.end();
271                }
272
273                //////////////////////////////////////////////////////////////////////////
274                /// Write a value to the resulting context.
275                ///
276                /// @param key The key to write to
277                /// @param value The value to write
278                ///
279                /// @author mickem
280                virtual void set_real_value(settings_core::key_path_type key, conainer value) {
281                        try {
282                                key = map.key(key);
283                                WritePrivateProfileString(key.first.c_str(), key.second.c_str(), value.get_string().c_str(), get_file_name().c_str());
284                        } catch (settings_exception e) {
285                                get_core()->get_logger()->err(__FILE__, __LINE__, std::wstring(_T("Failed to write key: ") + e.getError()));
286                        } catch (...) {
287                                get_core()->get_logger()->err(__FILE__, __LINE__, std::wstring(_T("Unknown filure when writing key: ") + key.first + _T(".") + key.second));
288                        }
289                }
290
291                virtual void set_real_path(std::wstring path) {
292                        // NOT Supported (and not needed) so silently ignored!
293                }
294
295                //////////////////////////////////////////////////////////////////////////
296                /// Get all (sub) sections (given a path).
297                /// If the path is empty all root sections will be returned
298                ///
299                /// @param path The path to get sections from (if empty root sections will be returned)
300                /// @param list The list to append nodes to
301                /// @return a list of sections
302                ///
303                /// @author mickem
304                virtual void get_real_sections(std::wstring path, string_list &list) {
305                        unsigned int path_length = path.length();
306                        map.get_sections(path, list);
307                        list.unique();
308                }
309
310                /**
311                * Retrieves a list of section
312                * @access public
313                * @returns INIFile::sectionList
314                * @qualifier
315                * @param unsigned int bufferLength
316                */
317                string_list int_read_sections(unsigned int bufferLength = BUFF_LEN) {
318                        string_list ret;
319                        TCHAR* buffer = new TCHAR[bufferLength+1];
320                        if (buffer == NULL)
321                                throw settings_exception(_T("getSections:: Failed to allocate memory for buffer!"));
322                        unsigned int count = ::GetPrivateProfileSectionNames(buffer, BUFF_LEN, get_file_name().c_str());
323                        if (count == bufferLength-2) {
324                                delete [] buffer;
325                                return int_read_sections(bufferLength*10);
326                        }
327                        unsigned int last = 0;
328                        for (unsigned int i=0;i<count;i++) {
329                                if (buffer[i] == '\0') {
330                                        std::wstring s = &buffer[last];
331                                        ret.push_back(s);
332                                        last = i+1;
333                                }
334                        }
335                        delete [] buffer;
336                        return ret;
337                }
338                //////////////////////////////////////////////////////////////////////////
339                /// Get all keys given a path/section.
340                /// If the path is empty all root sections will be returned
341                ///
342                /// @param path The path to get sections from (if empty root sections will be returned)
343                /// @param list The list to append nodes to
344                /// @return a list of sections
345                ///
346                /// @author mickem
347                virtual void get_real_keys(std::wstring path, string_list &list) {
348                        if (path.empty() || path == _T("/")) {
349                                get_core()->get_logger()->debug(__FILE__, __LINE__, std::wstring(_T("Loose leaves not supported: TODO")));
350                                return;
351                        }
352                        // @todo: this will NOT work for "nodes in paths"
353                        BOOST_FOREACH(settings_map::keys_key_type key, map.keys_) {
354                                if (path == key.first.first) {
355                                        if (has_key_int(key.second.first, key.second.second))
356                                                list.push_back(key.first.second);
357                                }
358                        }
359
360                        BOOST_FOREACH(settings_map::section_key_type key, map.sections_) {
361                                if (key.first == path) {
362                                        section_cache_type::const_iterator it = section_cache_.find(key.second);
363                                        if (it == section_cache_.end()) {
364                                                std::set<std::wstring> list = internal_read_keys_from_section(key.second);
365                                                section_cache_[path] = list;
366                                                it = section_cache_.find(path);
367                                        }
368                                        list.insert(list.end(), (*it).second.begin(), (*it).second.end());
369                                }
370                        }
371
372                }
373        private:
374
375                void int_read_section(std::wstring section, string_list &list, unsigned int bufferLength = BUFF_LEN) {
376                        TCHAR* buffer = new TCHAR[bufferLength+1];
377                        if (buffer == NULL)
378                                throw settings_exception(_T("getSections:: Failed to allocate memory for buffer!"));
379                        unsigned int count = GetPrivateProfileSection(section.c_str(), buffer, bufferLength, get_file_name().c_str());
380                        if (count == bufferLength-2) {
381                                delete [] buffer;
382                                int_read_section(section, list, bufferLength*10);
383                                return;
384                        }
385                        unsigned int last = 0;
386                        for (unsigned int i=0;i<count;i++) {
387                                if (buffer[i] == '\0') {
388                                        std::wstring s = &buffer[last];
389                                        std::size_t p = s.find('=');
390                                        if (p == std::wstring::npos)
391                                                list.push_back(s);
392                                        else
393                                                list.push_back(s.substr(0,p));
394                                        last = i+1;
395                                }
396                        }
397                        delete [] buffer;
398                }
399
400                string_list int_read_section_from_inifile(std::wstring section, unsigned int bufferLength = BUFF_LEN) {
401                        TCHAR* buffer = new TCHAR[bufferLength+1];
402                        if (buffer == NULL)
403                                throw settings_exception(_T("getSections:: Failed to allocate memory for buffer!"));
404                        unsigned int count = GetPrivateProfileSection(section.c_str(), buffer, bufferLength, get_file_name().c_str());
405                        if (count == bufferLength-2) {
406                                delete [] buffer;
407                                return int_read_section_from_inifile(section, bufferLength*10);
408                        }
409                        unsigned int last = 0;
410                        string_list list;
411                        for (unsigned int i=0;i<count;i++) {
412                                if (buffer[i] == '\0') {
413                                        std::wstring s = &buffer[last];
414                                        std::size_t p = s.find('=');
415                                        if (p == std::wstring::npos)
416                                                list.push_back(s);
417                                        else
418                                                list.push_back(s.substr(0,p));
419                                        last = i+1;
420                                }
421                        }
422                        delete [] buffer;
423                        return list;
424                }
425
426
427                inline std::wstring get_file_name() {
428                        if (filename_.empty()) {
429                                filename_ = get_file_from_context();
430                                //filename_ = (get_core()->get_base() / get_core()->get_boot_string(get_context(), _T("file"), _T("nsc.ini"))).string();
431                                get_core()->get_logger()->debug(__FILE__, __LINE__, _T("Reading old settings from: ") + filename_);
432                        }
433                        return filename_;
434                }
435                bool file_exists() {
436                        return boost::filesystem::is_regular_file(get_file_name());
437                }
438                virtual std::wstring get_info() {
439                        return _T("INI settings: (") + context_ + _T(", ") + get_file_name() + _T(")");
440                }
441        };
442}
Note: See TracBrowser for help on using the repository browser.