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