1 /*
2  * common/ConfigManager.cpp
3  *
4  * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity.
5  *
6  * Copyright 2009-2010 Andrew Ayer, Nathan Partlan, Jeffrey Pfau
7  *
8  * Leges Motus is free and open source software.  You may redistribute it and/or
9  * modify it under the terms of version 2, or (at your option) version 3, of the
10  * GNU General Public License (GPL), as published by the Free Software Foundation.
11  *
12  * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14  * PARTICULAR PURPOSE.  See the full text of the GNU General Public License for
15  * further detail.
16  *
17  * For a full copy of the GNU General Public License, please see the COPYING file
18  * in the root of the source code tree.  You may also retrieve a copy from
19  * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the
20  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307  USA
22  *
23  */
24 
25 #include "ConfigManager.hpp"
26 #include "StringTokenizer.hpp"
27 #include "misc.hpp"
28 #include <istream>
29 #include <ostream>
30 #include <fstream>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <limits>
35 #ifdef __WIN32
36 // Necessary to get SHGFP_TYPE_CURRENT
37 #ifndef _WIN32_IE
38 #define _WIN32_IE 0x0600
39 #endif
40 #include <Windows.h>
41 #include <shlobj.h>
42 #endif
43 
44 using namespace LM;
45 using namespace std;
46 
write_option(ostream & out,const ConfigManager::map_type::value_type & option)47 void	ConfigManager::write_option(ostream& out, const ConfigManager::map_type::value_type& option) {
48 	out << option.first << ' ' << option.second << '\n'; // TODO: format more nicely
49 }
50 
load(const char * filename)51 bool	ConfigManager::load(const char* filename) {
52 	ifstream	in(filename);
53 	return in && load(in);
54 }
55 
load(std::istream & in)56 bool	ConfigManager::load(std::istream& in) {
57 	string			line;
58 	while (getline(in, line)) {
59 		if (line.empty() || line[0] == '#' || line[0] == ';') {
60 			continue;
61 		}
62 
63 		StringTokenizer	tokenize(line, " \t", true, 2);
64 		string		name;
65 		tokenize >> name;
66 
67 		if (name.empty()) {
68 			continue;
69 		}
70 
71 		tokenize >> m_options[name];
72 	}
73 	return true;
74 }
75 
save(const char * filename) const76 bool	ConfigManager::save(const char* filename) const {
77 	ofstream	out(filename);
78 	return out && save(out);
79 }
80 
save(std::ostream & out) const81 bool	ConfigManager::save(std::ostream& out) const {
82 	map_type::const_iterator it(m_options.begin());
83 	while (it != m_options.end()) {
84 		write_option(out, *it++);
85 	}
86 	return true;
87 }
88 
load_system_config()89 bool	ConfigManager::load_system_config() {
90 	if (const char* path = system_config_path()) {
91 		return load(path);
92 	}
93 	return false;
94 }
95 
load_personal_config()96 bool	ConfigManager::load_personal_config() {
97 	if (const char* path = personal_config_path()) {
98 		return load(path);
99 	}
100 	return false;
101 }
102 
save_personal_config() const103 bool	ConfigManager::save_personal_config() const {
104 	if (const char* path = personal_config_path()) {
105 		return save(path);
106 	}
107 	return false;
108 }
109 
110 
lookup(const char * option_name) const111 const string*	ConfigManager::lookup(const char* option_name) const {
112 	map_type::const_iterator	it(m_options.find(option_name));
113 	return it != m_options.end() ? &it->second : NULL;
114 }
115 
operator [](const char * option_name) const116 const string&	ConfigManager::operator[](const char* option_name) const {
117 	if (const string* option_value = lookup(option_name)) {
118 		return *option_value;
119 	} else {
120 		return make_empty<string>();
121 	}
122 }
123 
124 
get(const char * option_name) const125 template<> string	ConfigManager::get(const char* option_name) const {
126 	const string* raw_value = lookup(option_name);
127 	return raw_value ? *raw_value : string();
128 }
129 
get(const char * option_name) const130 template<> const char*	ConfigManager::get(const char* option_name) const {
131 	const string* raw_value = lookup(option_name);
132 	return raw_value ? raw_value->c_str() : "";
133 }
134 
135 
get(const char * option_name) const136 template<> bool ConfigManager::get(const char* option_name) const {
137 	const string* raw_value = lookup(option_name);
138 
139 	return raw_value &&
140 		(atoi(raw_value->c_str()) > 0 ||
141 		 strcasecmp(raw_value->c_str(), "yes") == 0 ||
142 		 strcasecmp(raw_value->c_str(), "true") == 0 ||
143 		 strcasecmp(raw_value->c_str(), "on") == 0);
144 }
145 
set(const char * option_name,const bool & option_value)146 template<> void ConfigManager::set(const char* option_name, const bool& option_value) {
147 	m_options[option_name] = option_value ? "yes" : "no";
148 }
149 
get(const char * option_name) const150 template<> uint64_t	ConfigManager::get(const char* option_name) const {
151 	uint64_t	value = uint64_t();
152 	const string*	raw_value = lookup(option_name);
153 	if (raw_value && strcasecmp(raw_value->c_str(), "forever") == 0) {
154 		value = numeric_limits<uint64_t>::max();
155 	} else if (raw_value) {
156 		istringstream(*raw_value) >> value;
157 	}
158 	return value;
159 }
160 
set(const char * option_name,const uint64_t & option_value)161 template<> void	ConfigManager::set(const char* option_name, const uint64_t& option_value) {
162 	if (option_value == numeric_limits<uint64_t>::max()) {
163 		m_options[option_name] = "forever";
164 	} else {
165 		ostringstream	out;
166 		out << option_value;
167 		m_options[option_name] = out.str();
168 	}
169 }
170 
171 
set(const char * option_name,const char * const & option_value)172 template<> void ConfigManager::set(const char* option_name, const char* const& option_value) {
173 	m_options[option_name] = option_value;
174 }
175 
personal_config_path()176 const char*	ConfigManager::personal_config_path() {
177 	static string	path;
178 	if (path.empty()) {
179 #ifdef __WIN32
180 		TCHAR	appdata_path[MAX_PATH];
181 		if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata_path))) {
182 			path = appdata_path;
183 			path += "\\legesmotusrc.txt";
184 		} else {
185 			return NULL;
186 		}
187 #else
188 		if (const char* home_dir = getenv("HOME")) {
189 			path = home_dir;
190 			path += "/.legesmotusrc";
191 		} else {
192 			return NULL;
193 		}
194 #endif
195 	}
196 	return path.c_str();
197 }
198 
system_config_path()199 const char*	ConfigManager::system_config_path() { // TODO: use PREFIX/etc/legesmotusrc on UNIX
200 #ifdef __WIN32
201 	return "legesmotusrc.txt";
202 #else
203 	return "/etc/legesmotusrc";
204 #endif
205 }
206 
207