1 // Aseprite
2 // Copyright (C) 2001-2016 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/ini_file.h"
12
13 #include "app/resource_finder.h"
14 #include "base/fs.h"
15 #include "base/split_string.h"
16 #include "base/string.h"
17 #include "cfg/cfg.h"
18
19 #ifdef __APPLE__
20 #include "she/logger.h"
21 #include "she/system.h"
22 #endif
23
24 #ifndef _WIN32
25 #include "base/fs.h"
26 #endif
27
28 #include <cstdlib>
29 #include <vector>
30
31 namespace app {
32
33 using namespace gfx;
34
35 static std::string g_configFilename;
36 static std::vector<cfg::CfgFile*> g_configs;
37
ConfigModule()38 ConfigModule::ConfigModule()
39 {
40 ResourceFinder rf;
41 rf.includeUserDir("aseprite.ini");
42
43 // getFirstOrCreateDefault() will create the Aseprite directory
44 // inside the OS configuration folder (~/.config/aseprite/, etc.).
45 std::string fn = rf.getFirstOrCreateDefault();
46
47 #ifdef __APPLE__
48
49 // On OS X we migrate from ~/.config/aseprite/* -> "~/Library/Application Support/Aseprite/*"
50 if (!base::is_file(fn)) {
51 try {
52 std::string new_dir = base::get_file_path(fn);
53
54 // Now we try to move all old configuration files into the new
55 // directory.
56 ResourceFinder old_rf;
57 old_rf.includeHomeDir(".config/aseprite/aseprite.ini");
58 std::string old_config_fn = old_rf.defaultFilename();
59 if (base::is_file(old_config_fn)) {
60 std::string old_dir = base::get_file_path(old_config_fn);
61 for (std::string old_fn : base::list_files(old_dir)) {
62 std::string from = base::join_path(old_dir, old_fn);
63 std::string to = base::join_path(new_dir, old_fn);
64 base::move_file(from, to);
65 }
66 base::remove_directory(old_dir);
67 }
68 }
69 // Something failed
70 catch (const std::exception& ex) {
71 std::string err = "Error in configuration migration: ";
72 err += ex.what();
73
74 auto system = she::instance();
75 if (system && system->logger())
76 system->logger()->logError(err.c_str());
77 }
78 }
79
80 #elif !defined(_WIN32)
81
82 // On Linux we migrate the old configuration file name
83 // (.asepriterc -> ~/.config/aseprite/aseprite.ini)
84 {
85 ResourceFinder old_rf;
86 old_rf.includeHomeDir(".asepriterc");
87 std::string old_fn = old_rf.defaultFilename();
88 if (base::is_file(old_fn))
89 base::move_file(old_fn, fn);
90 }
91
92 #endif
93
94 set_config_file(fn.c_str());
95 g_configFilename = fn;
96 }
97
~ConfigModule()98 ConfigModule::~ConfigModule()
99 {
100 flush_config_file();
101
102 for (auto cfg : g_configs)
103 delete cfg;
104 g_configs.clear();
105 }
106
107 //////////////////////////////////////////////////////////////////////
108 // Allegro-like API to handle .ini configuration files
109
push_config_state()110 void push_config_state()
111 {
112 g_configs.push_back(new cfg::CfgFile());
113 }
114
pop_config_state()115 void pop_config_state()
116 {
117 ASSERT(!g_configs.empty());
118
119 delete g_configs.back();
120 g_configs.erase(--g_configs.end());
121 }
122
flush_config_file()123 void flush_config_file()
124 {
125 ASSERT(!g_configs.empty());
126
127 g_configs.back()->save();
128 }
129
set_config_file(const char * filename)130 void set_config_file(const char* filename)
131 {
132 if (g_configs.empty())
133 g_configs.push_back(new cfg::CfgFile());
134
135 g_configs.back()->load(filename);
136 }
137
main_config_filename()138 std::string main_config_filename()
139 {
140 return g_configFilename;
141 }
142
get_config_string(const char * section,const char * name,const char * value)143 const char* get_config_string(const char* section, const char* name, const char* value)
144 {
145 return g_configs.back()->getValue(section, name, value);
146 }
147
set_config_string(const char * section,const char * name,const char * value)148 void set_config_string(const char* section, const char* name, const char* value)
149 {
150 g_configs.back()->setValue(section, name, value);
151 }
152
get_config_int(const char * section,const char * name,int value)153 int get_config_int(const char* section, const char* name, int value)
154 {
155 return g_configs.back()->getIntValue(section, name, value);
156 }
157
set_config_int(const char * section,const char * name,int value)158 void set_config_int(const char* section, const char* name, int value)
159 {
160 g_configs.back()->setIntValue(section, name, value);
161 }
162
get_config_float(const char * section,const char * name,float value)163 float get_config_float(const char* section, const char* name, float value)
164 {
165 return (float)g_configs.back()->getDoubleValue(section, name, (float)value);
166 }
167
set_config_float(const char * section,const char * name,float value)168 void set_config_float(const char* section, const char* name, float value)
169 {
170 g_configs.back()->setDoubleValue(section, name, (float)value);
171 }
172
get_config_double(const char * section,const char * name,double value)173 double get_config_double(const char* section, const char* name, double value)
174 {
175 return g_configs.back()->getDoubleValue(section, name, value);
176 }
177
set_config_double(const char * section,const char * name,double value)178 void set_config_double(const char* section, const char* name, double value)
179 {
180 g_configs.back()->setDoubleValue(section, name, value);
181 }
182
get_config_bool(const char * section,const char * name,bool value)183 bool get_config_bool(const char* section, const char* name, bool value)
184 {
185 return g_configs.back()->getBoolValue(section, name, value);
186 }
187
set_config_bool(const char * section,const char * name,bool value)188 void set_config_bool(const char* section, const char* name, bool value)
189 {
190 g_configs.back()->setBoolValue(section, name, value);
191 }
192
get_config_point(const char * section,const char * name,const Point & point)193 Point get_config_point(const char* section, const char* name, const Point& point)
194 {
195 Point point2(point);
196 const char* value = get_config_string(section, name, "");
197 if (value) {
198 std::vector<std::string> parts;
199 base::split_string(value, parts, " ");
200 if (parts.size() == 2) {
201 point2.x = strtol(parts[0].c_str(), NULL, 10);
202 point2.y = strtol(parts[1].c_str(), NULL, 10);
203 }
204 }
205 return point2;
206 }
207
set_config_point(const char * section,const char * name,const Point & point)208 void set_config_point(const char* section, const char* name, const Point& point)
209 {
210 char buf[128];
211 sprintf(buf, "%d %d", point.x, point.y);
212 set_config_string(section, name, buf);
213 }
214
get_config_rect(const char * section,const char * name,const Rect & rect)215 Rect get_config_rect(const char* section, const char* name, const Rect& rect)
216 {
217 Rect rect2(rect);
218 const char* value = get_config_string(section, name, "");
219 if (value) {
220 std::vector<std::string> parts;
221 base::split_string(value, parts, " ");
222 if (parts.size() == 4) {
223 rect2.x = strtol(parts[0].c_str(), NULL, 10);
224 rect2.y = strtol(parts[1].c_str(), NULL, 10);
225 rect2.w = strtol(parts[2].c_str(), NULL, 10);
226 rect2.h = strtol(parts[3].c_str(), NULL, 10);
227 }
228 }
229 return rect2;
230 }
231
set_config_rect(const char * section,const char * name,const Rect & rect)232 void set_config_rect(const char* section, const char* name, const Rect& rect)
233 {
234 char buf[128];
235 sprintf(buf, "%d %d %d %d", rect.x, rect.y, rect.w, rect.h);
236 set_config_string(section, name, buf);
237 }
238
get_config_color(const char * section,const char * name,const app::Color & value)239 app::Color get_config_color(const char* section, const char* name, const app::Color& value)
240 {
241 return app::Color::fromString(get_config_string(section, name, value.toString().c_str()));
242 }
243
set_config_color(const char * section,const char * name,const app::Color & value)244 void set_config_color(const char* section, const char* name, const app::Color& value)
245 {
246 set_config_string(section, name, value.toString().c_str());
247 }
248
del_config_value(const char * section,const char * name)249 void del_config_value(const char* section, const char* name)
250 {
251 g_configs.back()->deleteValue(section, name);
252 }
253
254 } // namespace app
255