commit ec64bf03
Merge pull request #10 from sum01/C++11
C++11 & more
Changed files
diff --git a/.astylerc b/.astylerc
new file mode 100644
index 0000000..a131157
--- /dev/null
+++ b/.astylerc
@@ -0,0 +1,8 @@
+-t
+-j
+-y
+-c
+-k1
+-z2
+-A2
+--pad-header
diff --git a/.travis.yml b/.travis.yml
index 9f7a3f4..cad7ff4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,5 +30,9 @@ before_script:
script:
# Run cmake, then compile and run tests with make
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. && make -j$(nproc) && make test
+after_failure:
+ # Dumps any logs so you can read the stderr
+ - if [[ -e 'Testing/Temporary/LastTest.log' ]]; then cat 'Testing/Temporary/LastTest.log'; fi
+ - if [[ -e 'CMakeFiles/CMakeError.log' ]]; then cat 'CMakeFiles/CMakeError.log'; fi
notifications:
email: false
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 28a8297..e82cf99 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,25 +1,44 @@
-cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
+# For target_compile_features
+cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
project(platform_folders VERSION 3.2.0 LANGUAGES CXX)
# Since it's off, the library will be static by default
option(BUILD_SHARED_LIBS "Build shared instead of static." OFF)
-add_library(${PROJECT_NAME}
+add_library(platform_folders
sago/platform_folders.cpp
)
-# Where to search for the header
-# The BUILD/INSTALL interface expressions are for exporting
-target_include_directories(${PROJECT_NAME} PRIVATE
+# Defines standardized defaults for install paths
+include(GNUInstallDirs)
+# Where to search for the header while building
+target_include_directories(platform_folders PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/sago>
- $<INSTALL_INTERFACE:sago>
+ # Controls where #include <sago/platform_folders.h> starts to look from
+ # So /usr/include/<sago/platform_folders.h>
+ # or C:\Program Files\platform_folders\include\<sago/platform_folders.h>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# Define the header as public for installation
-set_target_properties(${PROJECT_NAME} PROPERTIES
+set_target_properties(platform_folders PROPERTIES
PUBLIC_HEADER "sago/platform_folders.h"
)
+# cxx_std_11 requires v3.8
+if(CMAKE_VERSION VERSION_LESS "3.8.0")
+ # Use old method of forcing C++11
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED true)
+else()
+ # Require (minimum) C++11 when using header
+ # PRIVATE means only at compile time
+ target_compile_features(platform_folders PUBLIC cxx_std_11)
+endif()
+
+# cxx_nullptr exists in v3.1
+target_compile_features(platform_folders PRIVATE cxx_nullptr)
+
# Apple requires linking to CoreServices
# Check sys name instead of "APPLE" for cross-compilation
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
@@ -36,55 +55,56 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
endif()
# Link to the CoreServices framework. This also sets the correct linking options
# "If the library file is in a Mac OSX framework, the Headers directory of the framework will also be processed as a usage requirement."
- target_link_libraries(${PROJECT_NAME} PRIVATE "${_CoreServices_FRAMEWORK}")
+ target_link_libraries(platform_folders PRIVATE "${_CoreServices_FRAMEWORK}")
endif()
-# Defines standardized defaults for install paths
-include(GNUInstallDirs)
-# For the config and configversion macros
-include(CMakePackageConfigHelpers)
-
-# Controls what dir to prefix for the lib, so <sago/platform_folders.h>
-set(_PROJECT_INSTALL_PREFIX_DIR "sago")
-# Controls where the exports, config, and configversion files install to
-set(_PROJECT_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/${_PROJECT_INSTALL_PREFIX_DIR}")
+# Cmake's find_package search path is different based on the system
+# See https://cmake.org/cmake/help/latest/command/find_package.html for the list
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ # Controls where the exports, config, and configversion files install to
+ set(_PROJECT_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}/cmake")
+else()
+ # When calling find_package(<name>)
+ # it looks for /usr/lib/cmake/<name>/<name>Config.cmake
+ set(_PROJECT_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/platform_folders")
+endif()
# Gives "Make install" esque operations a location to install to...
# and creates a .cmake file to be exported
-install(TARGETS ${PROJECT_NAME}
- EXPORT "${PROJECT_NAME}-targets"
- LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/${_PROJECT_INSTALL_PREFIX_DIR}"
- ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/${_PROJECT_INSTALL_PREFIX_DIR}"
- # Tells it where to put your headers if any set by set_target_properties
- PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/${_PROJECT_INSTALL_PREFIX_DIR}"
- # Tells export where your includes folder is | Note that the private include path is not needed here
- INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/${_PROJECT_INSTALL_PREFIX_DIR}"
+install(TARGETS platform_folders
+ EXPORT "platform_folders-targets"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ # Tells it where to put the header files
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/sago"
)
# "The install(TARGETS) and install(EXPORT) commands work together to install a target and a file to help import it"
# Installs a cmake file which external projects can import.
-install(EXPORT "${PROJECT_NAME}-targets"
+install(EXPORT "platform_folders-targets"
+ NAMESPACE sago::
DESTINATION "${_PROJECT_INSTALL_CMAKE_DIR}"
)
# "The export command is used to generate a file exporting targets from a project build tree"
# Creates an import file for external projects which are aware of the build tree.
# May be useful for cross-compiling
-export(TARGETS ${PROJECT_NAME}
- FILE "${PROJECT_NAME}-exports.cmake"
+export(TARGETS platform_folders
+ FILE "platform_folders-exports.cmake"
)
-configure_package_config_file("${PROJECT_NAME}Config.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+# For the config and configversion macros
+include(CMakePackageConfigHelpers)
+
+configure_package_config_file("platform_foldersConfig.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/platform_foldersConfig.cmake"
# Tells the config file where it will be installed, so it can be correctly imported
INSTALL_DESTINATION "${_PROJECT_INSTALL_CMAKE_DIR}"
- # This passes the variables to the cmake.in file, which uses them
- PATH_VARS PROJECT_NAME
)
# Creates the project's ConfigVersion.cmake file
# This allows for find_package() to use a version in the call
-write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/platform_foldersConfigVersion.cmake"
# This'll require versioning in the project() call
VERSION ${CMAKE_PROJECT_VERSION}
# Just assuming Semver is followed
@@ -93,8 +113,8 @@ write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Con
# Install the ConfigVersion file, which is located in the build dir
install(FILES
- "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
- "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/platform_foldersConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/platform_foldersConfigVersion.cmake"
DESTINATION "${_PROJECT_INSTALL_CMAKE_DIR}"
)
@@ -102,17 +122,5 @@ install(FILES
include(CTest)
# BUILD_TESTING is defined (default ON) in CTest
if(BUILD_TESTING)
- set(_PROJECT_TEST_NAME "${PROJECT_NAME}_test")
- add_executable(${_PROJECT_TEST_NAME} platform_folders.cpp)
-
- target_link_libraries(${_PROJECT_TEST_NAME} PRIVATE ${PROJECT_NAME})
-
- # Since tests aren't installed, no reason to give it an INSTALL_INTERFACE
- target_include_directories(${_PROJECT_TEST_NAME} PRIVATE
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/sago>
- )
-
- # Creates the "MyTest" test that runs the test executable created above
- # This is triggered by things like "make test"
- add_test(NAME MyTest COMMAND ${_PROJECT_TEST_NAME})
+ add_subdirectory(test)
endif()
diff --git a/README.md b/README.md
index ba1e811..05479d9 100644
--- a/README.md
+++ b/README.md
@@ -1,81 +1,117 @@
# PlatformFolders [](https://travis-ci.org/sago007/PlatformFolders) [](https://ci.appveyor.com/project/sago007/platformfolders) [](https://raw.githubusercontent.com/sago007/PlatformFolders/master/LICENSE) [](https://gitter.im/PlatformFolders/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://www.codacy.com/app/github_43/PlatformFolders?utm_source=github.com&utm_medium=referral&utm_content=sago007/PlatformFolders&utm_campaign=Badge_Grade)
-A C++ library to look for special directories like "My Documents" and "%APPDATA%" so that you do not need to write Linux, Windows and Mac OS X specific code
+A C++ library to look for directories like `My Documents`, `~/.config`, `%APPDATA%`, etc. so that you do not need to write platform-specific code
-Can be found at: https://github.com/sago007/PlatformFolders
+[Source code](https://github.com/sago007/PlatformFolders) • [Latest release](https://github.com/sago007/PlatformFolders/releases/latest) • [Doxygen documentation](http://sago007.github.io/PlatformFolders/html/doxygen/)
-Releases can be downloaded here: https://github.com/sago007/PlatformFolders/releases
+## Rationale
-# Rationale
There are a lot of platform abstraction libraries available. You can get graphics abstraction libraries, GUI abstraction libraries and file abstraction libraries.
But folder abstraction seems to be more difficult.
My problem was that the code that found the place to save data was platform dependent. This cluttered my code and often I would not discover that it did not compile until moving it to the different platforms.
-I have written a bit more about it here: http://sago007.blogspot.dk/2015/10/abstraction-for-special-folders.html
+[I have written a bit more about it here.](http://sago007.blogspot.dk/2015/10/abstraction-for-special-folders.html)
There are some alternatives that you might consider instead:
- * QStandardPaths - http://doc.qt.io/qt-5/qstandardpaths.html
- * glib - https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html
+
+* [QStandardPaths](http://doc.qt.io/qt-5/qstandardpaths.html)
+* [glib](https://developer.gnome.org/glib/stable/glib-Miscellaneous-Utility-Functions.html)
Both are properly more mature than this library. However they are both parts of large frameworks and using them with libraries outside the framework may not be that simple.
-# Documentation
+## Operating System Support
+
+### Windows
+
+For Windows, the folders are fetched using SHGetFolderPath.
+
+The amount of supported folders differ from Windows version and this library targets XP and newer.\
+XP support will be dropped very soon.
+
+"Save Games" and "Downloads" should not be used, as they are undefined on XP.
+
+### Linux
+
+This library uses the [XDG user-dirs.](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
+
+It should work on any Unix system that has the following headers available: `pwd.h`, `unistd.h`, and `sys/types.h`
+
+### macOS
+
+Uses the deprecated FSFindFolder (there is no C++ alternative), which requires the CoreServices framework during linking.
+
+## Usage
+
+This project should be compatible with things like [Cmake's ExternalProject_Add](https://cmake.org/cmake/help/latest/module/ExternalProject.html?highlight=externalproject_add#command:externalproject_add) if you wish to use it in your project.
+
+You can also follow the [build step](#building) below to install at a system level, and use [Cmake's find_package](https://cmake.org/cmake/help/latest/command/find_package.html).
+
+```cmake
+# Specifying a version is optional -- note it follows by Semver
+find_package(platform_folders 3.1.0 REQUIRED)
+# Which creates the IMPORTED lib "sago::platform_folders"
+# Use it like so...
+target_link_libraries(EXEORLIBNAME PRIVATE sago::platform_folders)
+```
+
+Alternatively, you can just copy the [sago](https://github.com/sago007/PlatformFolders/tree/master/sago) folder into your program and manually link everything.
-Aside from this page there are also Doxygen available at http://sago007.github.io/PlatformFolders/html/doxygen/
+### Building
-# Windows support
-For Windows the folders are fetched using SHGetFolderPath.
-The amount of supported folders differ from Windows version and this library targets XP and newer... and I'll drop XP support very soon.
-Currently "Save Games" and "Downloads" should not be used as they are undefined on XP.
+**Notes:**
+* macOS requires the CoreServices framework during linking.
+* If you don't want to install, remove the `--target install` command.
-# Linux support
-In Linux a lot of these folders are not official defined. However this library uses XDG user dirs.
+Linux/macOS:
-# Mac OS X support
-Uses the deprecated FSFindFolder (there is no C++ alternative). It requires "-framework CoreServices" during linking.
+```
+mkdir -p build && cd build
+cmake -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release ..
+sudo cmake --build . --target install
+```
-# Usage
-Copy "sago/platform_files.cpp" and "sago/platform_fildes.h" to your program and make sure that the cpp file is compiled and linked.
+Windows:
-It is also possible to compile and it like:
```
-mkdir -p build
-cd build
-cmake ..
-make
+mkdir build && cd build
+cmake -DBUILD_TESTING=OFF ..
+runas /user:Administrator "cmake --build . --config Release --target install"
```
-Just be aware that Mac OS X requires "-framework CoreServices" during linking no matter the choice.
-# Hello World
+## Example Usage
This sample program gets all folders from the system:
-```
-#include <iostream>
-#include <stirng>
-#include <vector>
-#include "sago/platform_folders.h"
-using std::cout;
+```cpp
+#include <sago/platform_folders.h>
+#include <iostream>
+#include <string>
int main()
{
- cout << "Config: " << sago::getConfigHome() << "\n";
- cout << "Data: " << sago::getDataHome() << "\n";
- cout << "Cache: " << sago::getCacheDir() << "\n";
- cout << "Documents: " << sago::getDocumentsFolder() << "\n";
- cout << "Desktop: " << sago::getDesktopFolder() << "\n";
- cout << "Pictures: " << sago::getPicturesFolder() << "\n";
- cout << "Music: " << sago::getMusicFolder() << "\n";
- cout << "Video: " << sago::getVideoFolder() << "\n";
- cout << "Download: " << sago::getDownloadFolder1() << "\n";
- cout << "Save Games 1: " << sago::getSaveGamesFolder1() << "\n";
+ using std::cout;
+
+ cout << "Config: " << sago::getConfigHome() << '\n';
+ cout << "Data: " << sago::getDataHome() << '\n';
+ cout << "Cache: " << sago::getCacheDir() << '\n';
+ sago::PlatformFolders p;
+ cout << "Documents: " << p.getDocumentsFolder() << "\n";
+ cout << "Desktop: " << p.getDesktopFolder() << "\n";
+ cout << "Pictures: " << p.getPicturesFolder() << "\n";
+ cout << "Music: " << p.getMusicFolder() << "\n";
+ cout << "Video: " << p.getVideoFolder() << "\n";
+ cout << "Download: " << p.getDownloadFolder1() << "\n";
+ cout << "Save Games 1: " << p.getSaveGamesFolder1() << "\n";
return 0;
}
```
-The output on Linux would look like this:
+### Example Output
+
+#### On Linux
+
```
Config: /home/poul/.config
Data: /home/poul/.local/share
@@ -89,7 +125,8 @@ Download: /home/poul/Hentede filer
Save Games 1: /home/poul/.local/share
```
-On Windows it could be:
+#### On Windows
+
```
Config: C:\users\poul\Application Data
Data: C:\users\poul\Application Data
@@ -103,7 +140,8 @@ Download: C:\users\poul\Skrivebord
Save Games 1: C:\users\poul\Mine dokumenter\My Games
```
-On Mac OS X it could be:
+#### On macOS
+
```
Config: /Users/poul/Library/Application Support
Data: /Users/poul/Library/Application Support
@@ -117,16 +155,19 @@ Download: /Users/poul/Downloads
Save Games 1: /Users/poul/Library/Application Support
```
-# C++ support
-Versions up to 3.X.X should compile with any C++98 compiler.
-Versions from 4.0.0 and up requires a C++11 compatible compiler.
+## Compiler Compatibility
+
+Versions up to 3.X.X should compile with any C++98 compiler.\
+Versions from 4.0.0 and up require a C++11 compatible compiler.
The aim is to always support the default C++ compiler on the oldest supported version of Ubuntu. This is a very basic library and it is not supposed to force you to upgrade.
-# Encoding
-From version 3.0 UTF-8 is always used on Windows and will also be the default on almost any other system.
-Before version 3.0 Windows used ANSI encoding. Microsoft's default choice of UTF-16 is not compatible with platform independent code.
-Although the user may use an characters they want I recommend, that the program should not have non ASCII characters in the source code itself.
+## Encoding
+
+From version 3.0, Windows always encodes to UTF-8, and this will be the default on almost any other system.
+Before version 3.0, Windows was encoded in ANSI.
+Although the user may use any characters they want, I recommend that the program should have only ASCII characters in the source code itself.
# Licence
+
Provided under the MIT license for the same reason XDG is licensed under it. So that you can quickly copy-paste the methods you need or just include the "sago"-folder.
diff --git a/appveyor.yml b/appveyor.yml
index 860cb79..6a6ce96 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -63,12 +63,13 @@ build_script:
# to run your custom scripts instead of automatic tests
# The %CONFIGURATION% and %PLATFORM% variables are set from Appveyor as env-vars
test_script:
- - cmd: MSBuild.exe /p:Configuration="%CONFIGURATION%" /p:Platform="%PLATFORM%" /v:minimal "%APPVEYOR_BUILD_FOLDER%"\build\RUN_TESTS.vcxproj
+ - cmd: IF "%PLATFORM%"=="x86" (MSBuild.exe "%APPVEYOR_BUILD_FOLDER%"\build\RUN_TESTS.vcxproj /p:Configuration="%CONFIGURATION%" /p:Platform="Win32" /v:minimal /m) ELSE (MSBuild.exe "%APPVEYOR_BUILD_FOLDER%"\build\RUN_TESTS.vcxproj /p:Configuration="%CONFIGURATION%" /p:Platform="%PLATFORM%" /v:minimal /m)
#---------------------------------#
# global handlers #
#---------------------------------#
-# on build failure dump cmake err log
+# on build failure dump cmake and test err log
on_failure:
- cmd: IF exist "%APPVEYOR_BUILD_FOLDER%"\build\CMakeFiles\CMakeError.log (type "%APPVEYOR_BUILD_FOLDER%"\build\CMakeFiles\CMakeError.log)
+ - cmd: IF exist "%APPVEYOR_BUILD_FOLDER%"\build\Testing\Temporary\LastTest.log (type "%APPVEYOR_BUILD_FOLDER%"\build\Testing\Temporary\LastTest.log)
diff --git a/platform_foldersConfig.cmake.in b/platform_foldersConfig.cmake.in
index 6bd5004..f4a7964 100644
--- a/platform_foldersConfig.cmake.in
+++ b/platform_foldersConfig.cmake.in
@@ -1,3 +1,3 @@
@PACKAGE_INIT@
-include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/platform_folders-targets.cmake")
diff --git a/sago/platform_folders.cpp b/sago/platform_folders.cpp
index 34e6bae..c7b1709 100644
--- a/sago/platform_folders.cpp
+++ b/sago/platform_folders.cpp
@@ -29,22 +29,31 @@ SOFTWARE.
#include "platform_folders.h"
#include <iostream>
#include <stdexcept>
-#include <string.h>
#include <cstdio>
#include <cstdlib>
-#if defined(_WIN32)
+#ifdef _WIN32
+// Make sure we don't bring in all the extra junk with windows.h
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+// stringapiset.h depends on this
#include <windows.h>
+// For SUCCEEDED macro
+#include <winerror.h>
+// For WideCharToMultiByte
+#include <stringapiset.h>
+// For SHGetFolderPathW and various CSIDL "magic numbers"
#include <shlobj.h>
static std::string win32_utf16_to_utf8(const wchar_t* wstr) {
std::string res;
// If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result.
- int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
+ int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (actualSize > 0) {
//If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it.
std::vector<char> buffer(actualSize);
- actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), NULL, NULL);
+ actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], buffer.size(), nullptr, nullptr);
res = buffer.data();
}
if (actualSize == 0) {
@@ -58,7 +67,7 @@ static std::string win32_utf16_to_utf8(const wchar_t* wstr) {
static std::string GetWindowsFolder(int folderId, const char* errorMsg) {
wchar_t szPath[MAX_PATH];
szPath[0] = 0;
- if ( !SUCCEEDED( SHGetFolderPathW( NULL, folderId, NULL, 0, szPath ) ) ) {
+ if ( !SUCCEEDED( SHGetFolderPathW( nullptr, folderId, nullptr, 0, szPath ) ) ) {
throw std::runtime_error(errorMsg);
}
return win32_utf16_to_utf8(szPath);
@@ -151,7 +160,7 @@ static std::string getLinuxFolderDefault(const char* envName, const char* defaul
static void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) {
std::vector<char> buffer(envValue, envValue + std::strlen(envValue) + 1);
char* p = std::strtok ( &buffer[0], ":");
- while (p != NULL) {
+ while (p != nullptr) {
if (p[0] == '/') {
folders.push_back(p);
}
@@ -160,7 +169,7 @@ static void appendExtraFoldersTokenizer(const char* envName, const char* envValu
//The XDG documentation indicates that the folder should be ignored but that the program should continue.
std::cerr << "Skipping path \"" << p << "\" in \"" << envName << "\" because it does not start with a \"/\"\n";
}
- p = std::strtok (NULL, ":");
+ p = std::strtok (nullptr, ":");
}
}
@@ -178,7 +187,7 @@ static void appendExtraFolders(const char* envName, const char* defaultValue, st
namespace sago {
std::string getDataHome() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder");
@@ -188,7 +197,7 @@ std::string getDataHome() {
}
std::string getConfigHome() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
return GetMacFolder(kApplicationSupportFolderType, "Failed to find the Application Support Folder");
@@ -198,7 +207,7 @@ std::string getConfigHome() {
}
std::string getCacheDir() {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetAppDataLocal();
#elif defined(__APPLE__)
return GetMacFolder(kCachedDataFolderType, "Failed to find the Application Support Folder");
@@ -208,26 +217,22 @@ std::string getCacheDir() {
}
void appendAdditionalDataDirectories(std::vector<std::string>& homes) {
-#if defined(_WIN32)
+#ifdef _WIN32
homes.push_back(GetAppDataCommon());
-#elif defined(__APPLE__)
-#else
+#elif !defined(__APPLE__)
appendExtraFolders("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/", homes);
#endif
}
void appendAdditionalConfigDirectories(std::vector<std::string>& homes) {
-#if defined(_WIN32)
+#ifdef _WIN32
homes.push_back(GetAppDataCommon());
-#elif defined(__APPLE__)
-#else
+#elif !defined(__APPLE__)
appendExtraFolders("XDG_CONFIG_DIRS", "/etc/xdg", homes);
#endif
}
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFolders::PlatformFoldersData {
std::map<std::string, std::string> folders;
};
@@ -243,7 +248,6 @@ static void PlatformFoldersAddFromFile(const std::string& filename, std::map<std
std::string key = line.substr(0, splitPos);
std::string value = line.substr(splitPos+2, line.length()-splitPos-3);
folders[key] = value;
- //std::cout << key << " : " << value << "\n";
}
}
@@ -267,9 +271,7 @@ static void PlatformFoldersFillData(std::map<std::string, std::string>& folders)
#endif
PlatformFolders::PlatformFolders() {
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
this->data = new PlatformFolders::PlatformFoldersData();
try {
PlatformFoldersFillData(data->folders);
@@ -282,15 +284,13 @@ PlatformFolders::PlatformFolders() {
}
PlatformFolders::~PlatformFolders() {
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
delete this->data;
#endif
}
std::string PlatformFolders::getDocumentsFolder() const {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder");
#elif defined(__APPLE__)
return GetMacFolder(kDocumentsFolderType, "Failed to find Documents Folder");
@@ -300,7 +300,7 @@ std::string PlatformFolders::getDocumentsFolder() const {
}
std::string PlatformFolders::getDesktopFolder() const {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find Desktop folder");
#elif defined(__APPLE__)
return GetMacFolder(kDesktopFolderType, "Failed to find Desktop folder");
@@ -310,7 +310,7 @@ std::string PlatformFolders::getDesktopFolder() const {
}
std::string PlatformFolders::getPicturesFolder() const {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetWindowsFolder(CSIDL_MYPICTURES, "Failed to find My Pictures folder");
#elif defined(__APPLE__)
return GetMacFolder(kPictureDocumentsFolderType, "Failed to find Picture folder");
@@ -320,7 +320,7 @@ std::string PlatformFolders::getPicturesFolder() const {
}
std::string PlatformFolders::getDownloadFolder1() const {
-#if defined(_WIN32)
+#ifdef _WIN32
//Pre Vista. Files was downloaded to the desktop
return GetWindowsFolder(CSIDL_DESKTOP, "Failed to find My Downloads (Desktop) folder");
#elif defined(__APPLE__)
@@ -331,7 +331,7 @@ std::string PlatformFolders::getDownloadFolder1() const {
}
std::string PlatformFolders::getMusicFolder() const {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetWindowsFolder(CSIDL_MYMUSIC, "Failed to find My Music folder");
#elif defined(__APPLE__)
return GetMacFolder(kMusicDocumentsFolderType, "Failed to find Music folder");
@@ -341,7 +341,7 @@ std::string PlatformFolders::getMusicFolder() const {
}
std::string PlatformFolders::getVideoFolder() const {
-#if defined(_WIN32)
+#ifdef _WIN32
return GetWindowsFolder(CSIDL_MYVIDEO, "Failed to find My Video folder");
#elif defined(__APPLE__)
return GetMacFolder(kMovieDocumentsFolderType, "Failed to find Movie folder");
@@ -351,7 +351,7 @@ std::string PlatformFolders::getVideoFolder() const {
}
std::string PlatformFolders::getSaveGamesFolder1() const {
-#if defined(_WIN32)
+#ifdef _WIN32
//A dedicated Save Games folder was not introduced until Vista. For XP and older save games are most often saved in a normal folder named "My Games".
//Data that should not be user accessible should be placed under GetDataHome() instead
return GetWindowsFolder(CSIDL_PERSONAL, "Failed to find My Documents folder")+"\\My Games";
diff --git a/sago/platform_folders.h b/sago/platform_folders.h
index bd6c0d5..193fa4d 100644
--- a/sago/platform_folders.h
+++ b/sago/platform_folders.h
@@ -218,9 +218,7 @@ public:
private:
PlatformFolders(const PlatformFolders&);
PlatformFolders& operator=(const PlatformFolders&);
-#if defined(_WIN32)
-#elif defined(__APPLE__)
-#else
+#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFoldersData;
PlatformFoldersData* data;
#endif
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..8b11d44
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,50 @@
+# Create the tester lib
+add_library(platformfolders_internal_tester
+ "tester.cpp"
+)
+
+# cxx_std_11 requires v3.8
+if(CMAKE_VERSION VERSION_LESS "3.8.0")
+ # Use old method of forcing C++11
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED true)
+else()
+ # Require (minimum) C++11 when using header
+ # PRIVATE means only at compile time
+ target_compile_features(platformfolders_internal_tester
+ PUBLIC cxx_std_11
+ )
+endif()
+
+# cxx_range_for exists in v3.1
+target_compile_features(platformfolders_internal_tester
+ PRIVATE cxx_range_for
+)
+
+target_include_directories(platformfolders_internal_tester
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
+)
+
+# Easily define a new test to run
+macro(_def_test _name)
+ add_executable(${_name} "${_name}.cpp")
+ target_link_libraries(${_name} PRIVATE
+ platform_folders
+ platformfolders_internal_tester
+ )
+ add_test(NAME "${_name}" COMMAND "${_name}")
+endmacro()
+
+_def_test("appendAdditionalConfigDirectories")
+_def_test("appendAdditionalDataDirectories")
+_def_test("getCacheDir")
+_def_test("getConfigHome")
+_def_test("getDataHome")
+_def_test("getDesktopFolder")
+_def_test("getDocumentsFolder")
+_def_test("getDownloadFolder1")
+_def_test("getMusicFolder")
+_def_test("getPicturesFolder")
+_def_test("getSaveGamesFolder1")
+_def_test("getVideoFolder")
+_def_test("integration")
diff --git a/test/appendAdditionalConfigDirectories.cpp b/test/appendAdditionalConfigDirectories.cpp
new file mode 100644
index 0000000..d1e6c15
--- /dev/null
+++ b/test/appendAdditionalConfigDirectories.cpp
@@ -0,0 +1,11 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+#include <string>
+#include <vector>
+
+int main() {
+ std::vector<std::string> extraData;
+ sago::appendAdditionalConfigDirectories(extraData);
+ run_test(extraData);
+ return 0;
+}
diff --git a/test/appendAdditionalDataDirectories.cpp b/test/appendAdditionalDataDirectories.cpp
new file mode 100644
index 0000000..ab83d22
--- /dev/null
+++ b/test/appendAdditionalDataDirectories.cpp
@@ -0,0 +1,11 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+#include <string>
+#include <vector>
+
+int main() {
+ std::vector<std::string> extraData;
+ sago::appendAdditionalDataDirectories(extraData);
+ run_test(extraData);
+ return 0;
+}
diff --git a/test/getCacheDir.cpp b/test/getCacheDir.cpp
new file mode 100644
index 0000000..c7ae8d2
--- /dev/null
+++ b/test/getCacheDir.cpp
@@ -0,0 +1,7 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getCacheDir());
+ return 0;
+}
diff --git a/test/getConfigHome.cpp b/test/getConfigHome.cpp
new file mode 100644
index 0000000..4253257
--- /dev/null
+++ b/test/getConfigHome.cpp
@@ -0,0 +1,7 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getConfigHome());
+ return 0;
+}
diff --git a/test/getDataHome.cpp b/test/getDataHome.cpp
new file mode 100644
index 0000000..e7bd564
--- /dev/null
+++ b/test/getDataHome.cpp
@@ -0,0 +1,7 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getDataHome());
+ return 0;
+}
diff --git a/test/getDesktopFolder.cpp b/test/getDesktopFolder.cpp
new file mode 100644
index 0000000..1851d67
--- /dev/null
+++ b/test/getDesktopFolder.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getDesktopFolder());
+ sago::PlatformFolders p;
+ run_test(p.getDesktopFolder());
+ return 0;
+}
diff --git a/test/getDocumentsFolder.cpp b/test/getDocumentsFolder.cpp
new file mode 100644
index 0000000..02d4de8
--- /dev/null
+++ b/test/getDocumentsFolder.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getDocumentsFolder());
+ sago::PlatformFolders p;
+ run_test(p.getDocumentsFolder());
+ return 0;
+}
diff --git a/test/getDownloadFolder1.cpp b/test/getDownloadFolder1.cpp
new file mode 100644
index 0000000..1bc9042
--- /dev/null
+++ b/test/getDownloadFolder1.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getDownloadFolder1());
+ sago::PlatformFolders p;
+ run_test(p.getDownloadFolder1());
+ return 0;
+}
diff --git a/test/getMusicFolder.cpp b/test/getMusicFolder.cpp
new file mode 100644
index 0000000..946c353
--- /dev/null
+++ b/test/getMusicFolder.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getMusicFolder());
+ sago::PlatformFolders p;
+ run_test(p.getMusicFolder());
+ return 0;
+}
diff --git a/test/getPicturesFolder.cpp b/test/getPicturesFolder.cpp
new file mode 100644
index 0000000..b1e5c09
--- /dev/null
+++ b/test/getPicturesFolder.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getPicturesFolder());
+ sago::PlatformFolders p;
+ run_test(p.getPicturesFolder());
+ return 0;
+}
diff --git a/test/getSaveGamesFolder1.cpp b/test/getSaveGamesFolder1.cpp
new file mode 100644
index 0000000..4c68a6f
--- /dev/null
+++ b/test/getSaveGamesFolder1.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getSaveGamesFolder1());
+ sago::PlatformFolders p;
+ run_test(p.getSaveGamesFolder1());
+ return 0;
+}
diff --git a/test/getVideoFolder.cpp b/test/getVideoFolder.cpp
new file mode 100644
index 0000000..ec0be60
--- /dev/null
+++ b/test/getVideoFolder.cpp
@@ -0,0 +1,9 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+
+int main() {
+ run_test(sago::getVideoFolder());
+ sago::PlatformFolders p;
+ run_test(p.getVideoFolder());
+ return 0;
+}
diff --git a/test/integration.cpp b/test/integration.cpp
new file mode 100644
index 0000000..74a456a
--- /dev/null
+++ b/test/integration.cpp
@@ -0,0 +1,34 @@
+#include "tester.hpp"
+#include "../sago/platform_folders.h"
+#include <string>
+#include <vector>
+
+// This is all tests in one
+int main() {
+ // Test plain functions
+ run_test(sago::getConfigHome());
+ run_test(sago::getDataHome());
+ run_test(sago::getCacheDir());
+ // Test non-member functions
+ run_test(sago::getDesktopFolder());
+ run_test(sago::getDocumentsFolder());
+ run_test(sago::getDownloadFolder1());
+ run_test(sago::getPicturesFolder());
+ run_test(sago::getMusicFolder());
+ run_test(sago::getVideoFolder());
+ run_test(sago::getSaveGamesFolder1());
+ // Test class methods
+ sago::PlatformFolders p;
+ run_test(p.getDocumentsFolder());
+ run_test(p.getDesktopFolder());
+ run_test(p.getPicturesFolder());
+ run_test(p.getMusicFolder());
+ run_test(p.getVideoFolder());
+ run_test(p.getDownloadFolder1());
+ run_test(p.getSaveGamesFolder1());
+ // Test vector function
+ std::vector<std::string> extraData;
+ sago::appendAdditionalDataDirectories(extraData);
+ run_test(extraData);
+ return 0;
+}
diff --git a/test/tester.cpp b/test/tester.cpp
new file mode 100644
index 0000000..b90b4a9
--- /dev/null
+++ b/test/tester.cpp
@@ -0,0 +1,40 @@
+#include "tester.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+// This should be passed either be char* or std::string for this to work
+static void test_internal(const std::string& data) {
+ try {
+ // Check that it actually got anything
+ if (data.empty()) {
+ throw std::logic_error("Got empty data");
+ }
+ }
+ catch (const std::exception& e) {
+ // Take any standard exception & output its message
+ std::cerr << e.what() << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ catch (...) {
+ // If any non-std exception is thrown, also fail
+ std::cerr << "Unknown exception!" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+}
+
+// std::string is expected input
+void run_test(const std::string& input) {
+ test_internal(input);
+}
+
+// A special overload for the two funcs that take a vector
+void run_test(const std::vector<std::string>& vec) {
+ // Check each value for validity
+ for (const std::string& elem : vec) {
+ test_internal(elem);
+ }
+}
diff --git a/test/tester.hpp b/test/tester.hpp
new file mode 100644
index 0000000..65c8e0a
--- /dev/null
+++ b/test/tester.hpp
@@ -0,0 +1,13 @@
+#ifndef SAGO_TEST_HPP
+#define SAGO_TEST_HPP
+
+#include <string>
+#include <vector>
+
+// std::string is expected input
+void run_test(const std::string&);
+
+// A special overload for the two funcs that take a vector
+void run_test(const std::vector<std::string>&);
+
+#endif