diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..cfd826629 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/simpleini"] + path = third_party/simpleini + url = git@github.com:aseprite/simpleini.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4edb9c116..9dffbe15f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ set(LIBJPEG_DIR ${CMAKE_SOURCE_DIR}/third_party/jpeg) set(LIBPNG_DIR ${CMAKE_SOURCE_DIR}/third_party/libpng) set(LOADPNG_DIR ${CMAKE_SOURCE_DIR}/third_party/loadpng) set(MONGOOSE_DIR ${CMAKE_SOURCE_DIR}/third_party/mongoose) +set(SIMPLEINI_DIR ${CMAKE_SOURCE_DIR}/third_party/simpleini) set(TINYXML_DIR ${CMAKE_SOURCE_DIR}/third_party/tinyxml) set(ZLIB_DIR ${CMAKE_SOURCE_DIR}/third_party/zlib) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5498d9b14..664ecadbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ endif(MSVC) set(aseprite_libraries app-lib fixmath-lib + cfg-lib css-lib doc-lib raster-lib @@ -134,6 +135,9 @@ else() include_directories(${LOADPNG_DIR}) endif() +set(libs3rdparty simpleini ${libs3rdparty}) +include_directories(${SIMPLEINI_DIR}) + ###################################################################### # Add C++11 support only for our code (avoid Allegro) @@ -195,6 +199,7 @@ endif() # Aseprite Libraries (in preferred order to be built) add_subdirectory(base) +add_subdirectory(cfg) add_subdirectory(css) add_subdirectory(doc) add_subdirectory(filters) diff --git a/src/README.md b/src/README.md index 84fa85981..3274f17c8 100644 --- a/src/README.md +++ b/src/README.md @@ -22,7 +22,7 @@ because they don't depend on any other component. ## Level 1 - * [cfg](cfg/) (base, allegro): Library to handle configuration/settings/user preferences. + * [cfg](cfg/) (base): Library to load/save .ini files. * [gen](gen/) (base): Helper utility to generate C++ files from different XMLs. * [net](net/) (base): Networking library to send HTTP requests. * [raster](raster/) (base, gfx): Library to handle graphics entities like sprites, images, frames. diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp index eb700c831..3c26130b7 100644 --- a/src/app/commands/cmd_options.cpp +++ b/src/app/commands/cmd_options.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -197,7 +197,7 @@ private: } void onLocateConfigFile() { - app::launcher::open_folder(app::get_config_file()); + app::launcher::open_folder(app::main_config_filename()); } ISettings* m_settings; diff --git a/src/app/file/jpeg_format.cpp b/src/app/file/jpeg_format.cpp index 6843bb6bf..a45f6dfaa 100644 --- a/src/app/file/jpeg_format.cpp +++ b/src/app/file/jpeg_format.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ #include "app/file/format_options.h" #include "app/find_widget.h" #include "app/ini_file.h" +#include "app/ini_file.h" #include "app/load_widget.h" #include "base/file_handle.h" #include "base/memory.h" diff --git a/src/app/ini_file.cpp b/src/app/ini_file.cpp index 3c8285d3e..85956d83f 100644 --- a/src/app/ini_file.cpp +++ b/src/app/ini_file.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,20 +23,22 @@ #include "app/ini_file.h" #include "app/resource_finder.h" +#include "base/split_string.h" +#include "base/string.h" +#include "cfg/cfg.h" #ifndef WIN32 #include "base/fs.h" #endif -#include -#include -#include +#include namespace app { using namespace gfx; static std::string g_configFilename; +static std::vector g_configs; ConfigModule::ConfigModule() { @@ -61,59 +63,118 @@ ConfigModule::ConfigModule() ConfigModule::~ConfigModule() { flush_config_file(); + + for (auto cfg : g_configs) + delete cfg; + g_configs.clear(); } -std::string get_config_file() +////////////////////////////////////////////////////////////////////// +// Allegro-like API to handle .ini configuration files + +void push_config_state() +{ + g_configs.push_back(new cfg::CfgFile()); +} + +void pop_config_state() +{ + ASSERT(!g_configs.empty()); + + delete g_configs.back(); + g_configs.erase(--g_configs.end()); +} + +void flush_config_file() +{ + ASSERT(!g_configs.empty()); + + g_configs.back()->save(); +} + +void set_config_file(const char* filename) +{ + if (g_configs.empty()) + g_configs.push_back(new cfg::CfgFile()); + + g_configs.back()->load(filename); +} + +std::string main_config_filename() { return g_configFilename; } -bool get_config_bool(const char *section, const char *name, bool value) +const char* get_config_string(const char* section, const char* name, const char* value) { - const char *got = get_config_string(section, name, value ? "yes": "no"); - return (got && - (ustricmp(got, "yes") == 0 || - ustricmp(got, "true") == 0 || - ustricmp(got, "1") == 0)) ? true: false; + return g_configs.back()->getValue(section, name, value); } -void set_config_bool(const char *section, const char *name, bool value) +void set_config_string(const char* section, const char* name, const char* value) { - set_config_string(section, name, value ? "yes": "no"); + g_configs.back()->setValue(section, name, value); } -Rect get_config_rect(const char *section, const char *name, const Rect& rect) +int get_config_int(const char* section, const char* name, int value) +{ + return g_configs.back()->getIntValue(section, name, value); +} + +void set_config_int(const char* section, const char* name, int value) +{ + g_configs.back()->setIntValue(section, name, value); +} + +float get_config_float(const char* section, const char* name, float value) +{ + return g_configs.back()->getDoubleValue(section, name, value); +} + +void set_config_float(const char* section, const char* name, float value) +{ + g_configs.back()->setDoubleValue(section, name, value); +} + +bool get_config_bool(const char* section, const char* name, bool value) +{ + return g_configs.back()->getBoolValue(section, name, value); +} + +void set_config_bool(const char* section, const char* name, bool value) +{ + g_configs.back()->setBoolValue(section, name, value); +} + +Rect get_config_rect(const char* section, const char* name, const Rect& rect) { Rect rect2(rect); - char **argv; - int argc; - - argv = get_config_argv(section, name, &argc); - - if (argv && argc == 4) { - rect2.x = ustrtol(argv[0], NULL, 10); - rect2.y = ustrtol(argv[1], NULL, 10); - rect2.w = ustrtol(argv[2], NULL, 10); - rect2.h = ustrtol(argv[3], NULL, 10); + const char* value = get_config_string(section, name, ""); + if (value) { + std::vector parts; + base::split_string(value, parts, " "); + if (parts.size() == 4) { + rect2.x = strtol(parts[0].c_str(), NULL, 10); + rect2.y = strtol(parts[1].c_str(), NULL, 10); + rect2.w = strtol(parts[2].c_str(), NULL, 10); + rect2.h = strtol(parts[3].c_str(), NULL, 10); + } } - return rect2; } -void set_config_rect(const char *section, const char *name, const Rect& rect) +void set_config_rect(const char* section, const char* name, const Rect& rect) { char buf[128]; - uszprintf(buf, sizeof(buf), "%d %d %d %d", - rect.x, rect.y, rect.w, rect.h); + sprintf(buf, "%d %d %d %d", rect.x, rect.y, rect.w, rect.h); set_config_string(section, name, buf); } -app::Color get_config_color(const char *section, const char *name, const app::Color& value) +app::Color get_config_color(const char* section, const char* name, const app::Color& value) { return app::Color::fromString(get_config_string(section, name, value.toString().c_str())); } -void set_config_color(const char *section, const char *name, const app::Color& value) +void set_config_color(const char* section, const char* name, const app::Color& value) { set_config_string(section, name, value.toString().c_str()); } diff --git a/src/app/ini_file.h b/src/app/ini_file.h index a08a58f1f..ac62e67a7 100644 --- a/src/app/ini_file.h +++ b/src/app/ini_file.h @@ -20,7 +20,6 @@ #define APP_INI_FILE_H_INCLUDED #pragma once -#include #include "gfx/rect.h" #include "app/color.h" @@ -32,16 +31,30 @@ namespace app { ~ConfigModule(); }; - std::string get_config_file(); + void push_config_state(); + void pop_config_state(); + void flush_config_file(); + void set_config_file(const char* filename); - bool get_config_bool(const char *section, const char *name, bool value); - void set_config_bool(const char *section, const char *name, bool value); + std::string main_config_filename(); - gfx::Rect get_config_rect(const char *section, const char *name, const gfx::Rect& rect); - void set_config_rect(const char *section, const char *name, const gfx::Rect& rect); + const char* get_config_string(const char* section, const char* name, const char* value); + void set_config_string(const char* section, const char* name, const char* value); - app::Color get_config_color(const char *section, const char *name, const app::Color& value); - void set_config_color(const char *section, const char *name, const app::Color& value); + int get_config_int(const char* section, const char* name, int value); + void set_config_int(const char* section, const char* name, int value); + + float get_config_float(const char* section, const char* name, float value); + void set_config_float(const char* section, const char* name, float value); + + bool get_config_bool(const char* section, const char* name, bool value); + void set_config_bool(const char* section, const char* name, bool value); + + gfx::Rect get_config_rect(const char* section, const char* name, const gfx::Rect& rect); + void set_config_rect(const char* section, const char* name, const gfx::Rect& rect); + + app::Color get_config_color(const char* section, const char* name, const app::Color& value); + void set_config_color(const char* section, const char* name, const app::Color& value); } // namespace app diff --git a/src/app/ini_file_tests.cpp b/src/app/ini_file_tests.cpp new file mode 100644 index 000000000..007a2e23a --- /dev/null +++ b/src/app/ini_file_tests.cpp @@ -0,0 +1,65 @@ +/* Aseprite + * Copyright (C) 2001-2014 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tests/test.h" + +#include "app/ini_file.h" +#include "base/fs.h" + +using namespace app; + +TEST(IniFile, Basic) +{ + if (base::is_file("_test.ini")) + base::delete_file("_test.ini"); + + set_config_file("_test.ini"); + + EXPECT_EQ(false, get_config_bool("A", "a", false)); + EXPECT_EQ(true, get_config_bool("A", "b", true)); + EXPECT_EQ(0, get_config_bool("B", "a", 0)); + EXPECT_EQ(1, get_config_bool("B", "b", 1)); + + set_config_bool("A", "a", true); + set_config_bool("A", "b", false); + set_config_int("B", "a", 2); + set_config_int("B", "b", 3); + + EXPECT_EQ(true, get_config_bool("A", "a", false)); + EXPECT_EQ(false, get_config_bool("A", "b", true)); + EXPECT_EQ(2, get_config_int("B", "a", 0)); + EXPECT_EQ(3, get_config_int("B", "b", 1)); +} + +TEST(IniFile, PushPop) +{ + if (base::is_file("_a.ini")) base::delete_file("_a.ini"); + if (base::is_file("_b.ini")) base::delete_file("_b.ini"); + + set_config_file("_a.ini"); + set_config_int("A", "a", 32); + + push_config_state(); + set_config_file("_b.ini"); + set_config_int("A", "a", 64); + EXPECT_EQ(64, get_config_int("A", "a", 0)); + pop_config_state(); + + EXPECT_EQ(32, get_config_int("A", "a", 0)); +} + diff --git a/src/app/modules/gfx.cpp b/src/app/modules/gfx.cpp index 3f2ef4046..17c70d412 100644 --- a/src/app/modules/gfx.cpp +++ b/src/app/modules/gfx.cpp @@ -1,5 +1,5 @@ /* Aseprite - * Copyright (C) 2001-2013 David Capello + * Copyright (C) 2001-2014 David Capello * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,6 @@ #include "app/app.h" #include "app/color_utils.h" #include "app/console.h" -#include "app/ini_file.h" #include "app/modules/gfx.h" #include "app/modules/gui.h" #include "app/modules/palettes.h" diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 26d4045bb..659633c77 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -43,3 +43,5 @@ endif() if(ENABLE_WEBSERVER) add_subdirectory(mongoose) endif() + +add_subdirectory(simpleini) diff --git a/third_party/simpleini b/third_party/simpleini new file mode 160000 index 000000000..d4a436a8a --- /dev/null +++ b/third_party/simpleini @@ -0,0 +1 @@ +Subproject commit d4a436a8adfbc7f611313803d776e6c1f48dad91