diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh index 3b6c860..85ac203 100755 --- a/.devcontainer/setup.sh +++ b/.devcontainer/setup.sh @@ -69,3 +69,15 @@ if ! command -v zig; then curl -sS https://webi.sh/zig | sh source ~/.config/envman/PATH.env fi + +if ! command -v cmake-format; then + if ! command -v pipx; then + pip install pipx + fi + pipx install cmake-format +fi + +if ! command -v doxygen; then + sudo apt-get update + sudo apt-get install -y doxygen +fi diff --git a/.github/workflows/cmake-workflow-preset-docs.yml b/.github/workflows/cmake-workflow-preset-docs.yml new file mode 100644 index 0000000..e69de29 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2554d15..2a70f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,35 +1,136 @@ cmake_minimum_required(VERSION 3.29) -project(platformdirs - VERSION 4.2.2 - LANGUAGES CXX -) -set(project_definitions PROJECT_NAME="${PROJECT_NAME}" PROJECT_VERSION="${PROJECT_VERSION}" PROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} PROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} PROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} PROJECT_VERSION_TWEAK=${PROJECT_VERSION_TWEAK}) +# Project declaration +project( + platformdirs + VERSION 0.1.0 + DESCRIPTION "📂 Python's platformdirs module for C++" + HOMEPAGE_URL "https://jcbhmr.me/platformdirs" + LANGUAGES CXX) +# Main dependencies include(FetchContent) -FetchContent_Declare(fmt +FetchContent_Declare( + fmt GIT_REPOSITORY https://github.com/fmtlib/fmt.git - GIT_TAG 11.0.2 -) - -# FMT_OS doesn't work with cosmocc + GIT_TAG 11.0.2 + FIND_PACKAGE_ARGS 11.0.2...<12) +# FMT_OS doesn't work with Cosmopolitan set(FMT_OS OFF) FetchContent_MakeAvailable(fmt) +# Library targets add_library(platformdirs) -target_sources(platformdirs PRIVATE src/platformdirs/api.cpp src/platformdirs/unix.cpp src/platformdirs/utils.cpp src/platformdirs/version.cpp) +add_library(platformdirs::platformdirs ALIAS platformdirs) +target_sources( + platformdirs + PRIVATE src/platformdirs.cpp + src/platformdirs/api.cpp + src/platformdirs/macos.cpp + src/platformdirs/unix.cpp + src/platformdirs/utils.cpp + src/platformdirs/version.cpp + src/platformdirs/windows.cpp) target_include_directories(platformdirs PUBLIC include) target_compile_features(platformdirs PRIVATE cxx_std_23) # cosmocc has exceptions off by default target_compile_options(platformdirs PRIVATE -fexceptions) target_link_libraries(platformdirs PRIVATE fmt::fmt) -target_compile_definitions(platformdirs PRIVATE ${project_definitions}) +target_compile_definitions(platformdirs PRIVATE +PROJECT_VERSION="${PROJECT_VERSION}" +PROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} +PROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} +PROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} +PROJECT_VERSION_TWEAK=${PROJECT_VERSION_TWEAK}) +# Binary targets add_executable(platformdirs_exe) +add_executable(platformdirs::platformdirs_exe ALIAS platformdirs_exe) set_property(TARGET platformdirs_exe PROPERTY OUTPUT_NAME platformdirs) target_sources(platformdirs_exe PRIVATE src/platformdirs_exe.cpp) target_compile_features(platformdirs_exe PRIVATE cxx_std_23) # cosmocc has exceptions off by default target_compile_options(platformdirs_exe PRIVATE -fexceptions) target_link_libraries(platformdirs_exe PRIVATE fmt::fmt platformdirs) -target_compile_definitions(platformdirs_exe PRIVATE ${project_definitions}) +target_compile_definitions(platformdirs_exe PRIVATE +PROJECT_VERSION="${PROJECT_VERSION}" +PROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} +PROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} +PROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} +PROJECT_VERSION_TWEAK=${PROJECT_VERSION_TWEAK}) + +# Testing +include(CTest) +if(BUILD_TESTING) + add_test(NAME platformdirs COMMAND platformdirs_exe) +endif() + +# Packaging +include(CPack) + +# Installation +include(GNUInstallDirs) +install(TARGETS platformdirs platformdirs_exe) + +# Tasks +if(BUILD_TESTING) +file( + GLOB_RECURSE + c_cxx_files + src/*.c + src/*.cpp + src/*.cc + src/*.cxx + src/*.h + src/*.hxx + src/*.hh + src/*.hpp + include/*.h + include/*.hxx + include/*.hh + include/*.hpp + test/*.c + test/*.cpp + test/*.cc + test/*.cxx + test/*.h + test/*.hxx + test/*.hh + test/*.hpp + examples/*.c + examples/*.cpp + examples/*.cc + examples/*.cxx + examples/*.h + examples/*.hxx + examples/*.hh + examples/*.hpp) + file( + GLOB_RECURSE + cmake_files + cmake/*.cmake + src/*CMakeLists.txt + src/*.cmake + test/*CMakeLists.txt + test/*.cmake) + list(APPEND cmake_format_files CMakeLists.txt task.cmake) + add_custom_target(format + COMMAND clang-format -i ${c_cxx_files} + COMMAND cmake-format -i ${cmake_files} + COMMAND_ECHO STDERR + COMMAND_ERROR_IS_FATAL ANY + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + + file(GLOB_RECURSE all_files .github/* cmake/* src/* examples/* test/* docs/*) + list(APPEND .gitignore CMakeLists.txt CMakePresets.json README.md task.cmake) + add_custom_target(lint COMMAND codespell -w ${all_files} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + + find_package(Doxygen REQUIRED) + set(DOXYGEN_EXCLUDE "${CMAKE_BINARY_DIR}") + set(DOXYGEN_EXTRACT_ALL YES) + set(DOXYGEN_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include") + doxygen_add_docs(docs "${PROJECT_SOURCE_DIR}") + + add_custom_target(preview COMMAND python -m http.server WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html") + add_dependencies(preview docs) +endif() diff --git a/CMakePresets.json b/CMakePresets.json index 84f4a50..faa41da 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -48,37 +48,37 @@ }, { "name": "zig-cc-target-arm64-linux-musl", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-arm64-linux-musl.cmake", "binaryDir": "build/zig-cc-target-arm64-linux-musl" }, { "name": "zig-cc-target-arm64-macos-none", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-arm64-macos-none.cmake", "binaryDir": "build/zig-cc-target-arm64-macos-none" }, { "name": "zig-cc-target-wasm32-wasi-musl", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-wasm32-wasi-musl.cmake", "binaryDir": "build/zig-cc-target-wasm32-wasi-musl" }, { "name": "zig-cc-target-x86_64-linux-musl", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-x86_64-linux-musl.cmake", "binaryDir": "build/zig-cc-target-x86_64-linux-musl" }, { "name": "zig-cc-target-x86_64-macos-none", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-x86_64-macos-none.cmake", "binaryDir": "build/zig-cc-target-x86_64-macos-none" }, { "name": "zig-cc-target-x86_64-windows-gnu", - "inherits": ["default"], + "inherits": ["zig-cc"], "toolchainFile": "cmake/zig-cc-target-x86_64-windows-gnu.cmake", "binaryDir": "build/zig-cc-target-x86_64-windows-gnu" } @@ -91,17 +91,105 @@ }, { "name": "release", + "inherits": ["default"], "configurePreset": "release", "configuration": "Release" }, + { + "name": "clang", + "inherits": ["default"], + "configurePreset": "clang" + }, { "name": "cosmocc", - "configurePreset": "cosmocc", - "configuration": "Debug" + "inherits": ["default"], + "configurePreset": "cosmocc" + }, + { + "name": "gcc", + "inherits": ["default"], + "configurePreset": "gcc" + }, + { + "name": "zig-cc", + "inherits": ["default"], + "configurePreset": "zig-cc" + }, + { + "name": "zig-cc-target-arm64-linux-musl", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-arm64-linux-musl" + }, + { + "name": "zig-cc-target-arm64-macos-none", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-arm64-macos-none" + }, + { + "name": "zig-cc-target-wasm32-wasi-musl", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-wasm32-wasi-musl" + }, + { + "name": "zig-cc-target-x86_64-linux-musl", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-x86_64-linux-musl" + }, + { + "name": "zig-cc-target-x86_64-macos-none", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-x86_64-macos-none" + }, + { + "name": "zig-cc-target-x86_64-windows-gnu", + "inherits": ["zig-cc"], + "configurePreset": "zig-cc-target-x86_64-windows-gnu" + }, + { + "name": "format", + "inherits": ["default"], + "targets": ["format"] + }, + { + "name": "lint", + "inherits": ["default"], + "targets": ["lint"] + }, + { + "name": "docs", + "inherits": ["default"], + "targets": ["docs"] + }, + { + "name": "preview", + "inherits": ["default"], + "targets": ["preview"] + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "configuration": "Debug", + "output": { "outputOnFailure": true } + }, + { + "name": "cosmocc", + "inherits": ["default"], + "configurePreset": "cosmocc" + } + ], + "packagePresets": [ + { + "name": "default", + "configurePreset": "default" + }, + { + "name": "release", + "inherits": ["default"], + "configurePreset": "release" } ], - "testPresets": [], - "packagePresets": [], "workflowPresets": [ { "name": "default", @@ -117,12 +205,119 @@ { "type": "build", "name": "release" } ] }, + { + "name": "test", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "default" }, + { "type": "test", "name": "default" } + ] + }, + { + "name": "test-cosmocc", + "steps": [ + { "type": "configure", "name": "cosmocc" }, + { "type": "build", "name": "cosmocc" }, + { "type": "test", "name": "cosmocc" } + ] + }, + { + "name": "clang", + "steps": [ + { "type": "configure", "name": "clang" }, + { "type": "build", "name": "clang" } + ] + }, { "name": "cosmocc", "steps": [ { "type": "configure", "name": "cosmocc" }, { "type": "build", "name": "cosmocc" } ] + }, + { + "name": "gcc", + "steps": [ + { "type": "configure", "name": "gcc" }, + { "type": "build", "name": "gcc" } + ] + }, + { + "name": "zig-cc", + "steps": [ + { "type": "configure", "name": "zig-cc" }, + { "type": "build", "name": "zig-cc" } + ] + }, + { + "name": "zig-cc-target-arm64-linux-musl", + "steps": [ + { "type": "configure", "name": "zig-cc-target-arm64-linux-musl" }, + { "type": "build", "name": "zig-cc-target-arm64-linux-musl" } + ] + }, + { + "name": "zig-cc-target-arm64-macos-none", + "steps": [ + { "type": "configure", "name": "zig-cc-target-arm64-macos-none" }, + { "type": "build", "name": "zig-cc-target-arm64-macos-none" } + ] + }, + { + "name": "zig-cc-target-wasm32-wasi-musl", + "steps": [ + { "type": "configure", "name": "zig-cc-target-wasm32-wasi-musl" }, + { "type": "build", "name": "zig-cc-target-wasm32-wasi-musl" } + ] + }, + { + "name": "zig-cc-target-x86_64-linux-musl", + "steps": [ + { "type": "configure", "name": "zig-cc-target-x86_64-linux-musl" }, + { "type": "build", "name": "zig-cc-target-x86_64-linux-musl" } + ] + }, + { + "name": "zig-cc-target-x86_64-macos-none", + "steps": [ + { "type": "configure", "name": "zig-cc-target-x86_64-macos-none" }, + { "type": "build", "name": "zig-cc-target-x86_64-macos-none" } + ] + }, + { + "name": "zig-cc-target-x86_64-windows-gnu", + "steps": [ + { "type": "configure", "name": "zig-cc-target-x86_64-windows-gnu" }, + { "type": "build", "name": "zig-cc-target-x86_64-windows-gnu" } + ] + }, + { + "name": "format", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "format" } + ] + }, + { + "name": "lint", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "lint" } + ] + }, + { + "name": "docs", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "docs" } + ] + }, + { + "name": "preview", + "steps": [ + { "type": "configure", "name": "default" }, + { "type": "build", "name": "preview" } + ] } ] } diff --git a/README.md b/README.md index 30fc1e1..eaa3c4c 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,29 @@ TODO ## Installation +
+
CMake find_package() with FetchContent fallback +
+ ```cmake include(FetchContent) FetchContent_Declare(platformdirs GIT_REPOSITORY https://github.com/jcbhmr/platformdirs-cpp.git GIT_TAG v0.1.0 -) + FIND_PACKAGE_ARGS 0.1.0...<1) +# Will try find_package(platformdirs 0.1.0...<1) first FetchContent_MakeAvailable(platformdirs) -target_link_libraries(my-app platformdirs) + +# ... + +# Now link it into your app/lib target +target_link_libraries(myapp platformdirs::platformdirs) +target_link_libraries(mylib platformdirs::platformdirs) ``` -## Usage +
-
+## Usage
main.cpp
@@ -37,72 +47,20 @@ target_link_libraries(my-app platformdirs) #include int main() { - std::println("user config: {}", platformdirs::user_config_dir()); - std::println("user cache (myapp by me): {}", platformdirs::user_cache_dir("myapp", "me")); + std::println("my app config: {}", platformdirs::user_config_dir("myapp", "me", "1.2.3")); return 0; } ``` -
- -``` -user config: ~/.local/config -user cache (myapp by me): ~/.local/cache/me/myapp TODO! -``` - -
- -~~[📚 See the complete API surface on the website](https://jcbhmr.me/platformdirs/)~~ +[📚 See the complete API surface on the website](https://jcbhmr.me/platformdirs/) 💡 Pro tip: there's an included `platformdirs` executable which prints a report of all the config dirs for you. It's great for debugging! 😉 ## Development -
-
Compile everything using the system C/C++ toolchain -
- ```sh cmake --workflow --preset default -cmake --workflow --preset release +cmake --workflow --preset test ``` -
Compile everything using a different C/C++ toolchain -
- -```sh -cmake --workflow --preset clang -cmake --workflow --preset cosmocc -cmake --workflow --preset gcc -cmake --workflow --preset zig-cc -cmake --workflow --preset zig-cc-target-wasm32-wasi-musl -cmake --workflow --preset zig-cc-target-* # There's more! -``` - -
Compile and run tests No tests right now -
- -```sh -cmake --workflow --preset test # (system toolchain) -cmake --workflow --preset test-cosmocc -``` - -
Run tasks defined in task.cmake -
- -```sh -cmake --workflow --preset format -cmake --workflow --preset lint -``` - -
Compile and package -
- -```sh -cmake --workflow --preset package # (system toolchain) -cmake --workflow --preset package-cosmocc -``` - -
- 💡 You can cut down on the repetative `cmake --workflow --preset` with an `alias cmakew="cmake --workflow --preset"` or similar. diff --git a/cmake/clang.cmake b/cmake/clang.cmake index 42fb1e3..4ea186d 100644 --- a/cmake/clang.cmake +++ b/cmake/clang.cmake @@ -1,5 +1,5 @@ set(CMAKE_ASM_COMPILER clang) set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) -set(CMAKE_AR llvm-ar) -set(CMAKE_RANLIB llvm-ranlib) +find_program(CMAKE_AR llvm-ar REQUIRED) +find_program(CMAKE_RANLIB llvm-ranlib REQUIRED) diff --git a/cmake/cosmocc-override.cmake b/cmake/cosmocc-override.cmake index b1a5161..09e7507 100644 --- a/cmake/cosmocc-override.cmake +++ b/cmake/cosmocc-override.cmake @@ -1,3 +1,3 @@ set(CMAKE_ASM_OUTPUT_EXTENSION .o) set(CMAKE_C_OUTPUT_EXTENSION .o) -set(CMAKE_CXX_OUTPUT_EXTENSION .o) \ No newline at end of file +set(CMAKE_CXX_OUTPUT_EXTENSION .o) diff --git a/cmake/cosmocc.cmake b/cmake/cosmocc.cmake index cd3d29d..3496fa0 100644 --- a/cmake/cosmocc.cmake +++ b/cmake/cosmocc.cmake @@ -4,6 +4,7 @@ unset(CMAKE_SYSTEM_PROCESSOR) set(CMAKE_ASM_COMPILER cosmocc) set(CMAKE_C_COMPILER cosmocc) set(CMAKE_CXX_COMPILER cosmoc++) -set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/cosmocc-override.cmake") +set(CMAKE_USER_MAKE_RULES_OVERRIDE + "${CMAKE_CURRENT_LIST_DIR}/cosmocc-override.cmake") find_program(CMAKE_AR cosmoar REQUIRED) unset(CMAKE_RANLIB) diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake index d163bdb..f325c5a 100644 --- a/cmake/gcc.cmake +++ b/cmake/gcc.cmake @@ -1,5 +1,5 @@ set(CMAKE_ASM_COMPILER gcc) set(CMAKE_C_COMPILER gcc) set(CMAKE_CXX_COMPILER g++) -set(CMAKE_AR gcc-ar) -set(CMAKE_RANLIB gcc-ranlib) +find_program(CMAKE_AR gcc-ar REQUIRED) +find_program(CMAKE_RANLIB gcc-ranlib REQUIRED) diff --git a/cmake/zig-cc-target-arm64-linux-musl.cmake b/cmake/zig-cc-target-arm64-linux-musl.cmake index 9228ae0..cd3e11f 100644 --- a/cmake/zig-cc-target-arm64-linux-musl.cmake +++ b/cmake/zig-cc-target-arm64-linux-musl.cmake @@ -8,5 +8,5 @@ set(target arm64-linux-musl) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc-target-arm64-macos-none.cmake b/cmake/zig-cc-target-arm64-macos-none.cmake index be578e3..17136fa 100644 --- a/cmake/zig-cc-target-arm64-macos-none.cmake +++ b/cmake/zig-cc-target-arm64-macos-none.cmake @@ -8,5 +8,5 @@ set(target arm64-macos-none) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc-target-wasm32-wasi-musl.cmake b/cmake/zig-cc-target-wasm32-wasi-musl.cmake index bd82ed5..25315af 100644 --- a/cmake/zig-cc-target-wasm32-wasi-musl.cmake +++ b/cmake/zig-cc-target-wasm32-wasi-musl.cmake @@ -8,5 +8,5 @@ set(target wasm32-wasi-musl) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc-target-x86_64-linux-musl.cmake b/cmake/zig-cc-target-x86_64-linux-musl.cmake index 083698f..6f7edfb 100644 --- a/cmake/zig-cc-target-x86_64-linux-musl.cmake +++ b/cmake/zig-cc-target-x86_64-linux-musl.cmake @@ -8,5 +8,5 @@ set(target x86_64-linux-musl) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc-target-x86_64-macos-none.cmake b/cmake/zig-cc-target-x86_64-macos-none.cmake index 9ed9ce1..d238fec 100644 --- a/cmake/zig-cc-target-x86_64-macos-none.cmake +++ b/cmake/zig-cc-target-x86_64-macos-none.cmake @@ -8,5 +8,5 @@ set(target x86_64-macos-none) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc-target-x86_64-windows-gnu.cmake b/cmake/zig-cc-target-x86_64-windows-gnu.cmake index bc4b016..ed3ffe2 100644 --- a/cmake/zig-cc-target-x86_64-windows-gnu.cmake +++ b/cmake/zig-cc-target-x86_64-windows-gnu.cmake @@ -8,5 +8,5 @@ set(target x86_64-windows-gnu) set(CMAKE_ASM_COMPILER_TARGET "${target}") set(CMAKE_C_COMPILER_TARGET "${target}") set(CMAKE_CXX_COMPILER_TARGET "${target}") -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/cmake/zig-cc.cmake b/cmake/zig-cc.cmake index 2d50652..d11a067 100644 --- a/cmake/zig-cc.cmake +++ b/cmake/zig-cc.cmake @@ -1,5 +1,5 @@ set(CMAKE_ASM_COMPILER zig cc) set(CMAKE_C_COMPILER zig cc) set(CMAKE_CXX_COMPILER zig c++) -set(CMAKE_AR "${CMAKE_CURRENT_SOURCE_DIR}/zig-ar") -set(CMAKE_RANLIB "${CMAKE_CURRENT_SOURCE_DIR}/zig-ranlib") +find_program(CMAKE_AR "${CMAKE_CURRENT_LIST_DIR}/zig-ar" REQUIRED) +find_program(CMAKE_RANLIB "${CMAKE_CURRENT_LIST_DIR}/zig-ranlib" REQUIRED) diff --git a/include/platformdirs.h b/include/platformdirs.h index ee9c8b4..0b3ec6e 100644 --- a/include/platformdirs.h +++ b/include/platformdirs.h @@ -1,12 +1,21 @@ #pragma once + +/*! \mainpage + * + */ + #undef unix +#include "platformdirs/api.h" +#include "platformdirs/version.h" #include #include #include -#include "platformdirs/version.h" - +#include #if __COSMOPOLITAN__ -#include "platformdirs/cosmopolitan.h" +#include "platformdirs/macos.h" +#include "platformdirs/unix.h" +#include "platformdirs/windows.h" +#include #elif __APPLE__ #include "platformdirs/macos.h" #elif _WIN32 @@ -17,23 +26,222 @@ namespace platformdirs { -using version_ = platformdirs::version::version; +/** Renamed slightly because there's a module name (namespace) and function name with the same "version" identifier. */ +constexpr auto &version_ = platformdirs::version::version; -using platformdirs::version::version_tuple; +constexpr auto &version_info = platformdirs::version::version_tuple; -using platform_dirs = #if __COSMOPOLITAN__ -platformdirs::cosmopolitan::cosmopolitan; -#elif __APPLE__ +/** + * Newtype wrapper around std::variant<...> of the implementations. We can't + * determine the operating system at compile-time since Cosmopolitan Libc + * allows a single binary to run on a variety of platforms. Thus, we need to + * choose the OS-specific implementation at runtime. + */ +class platform_dirs { +public: + std::variant + value; + +public: + platform_dirs(const std::optional &appname = std::nullopt, + const std::variant + &appauthor = std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool multipath = false, + bool opinion = true, bool ensure_exists = false) { + if (IsWindows()) { + this->value = + platformdirs::windows::windows(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists); + } else if (IsXnu()) { + this->value = + platformdirs::macos::macos(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists); + } else { + this->value = + platformdirs::unix::unix(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists); + } + } + + std::string user_data_dir() const { + return std::visit([](auto &&arg) { return arg.user_data_dir(); }, + this->value); + } + + std::string site_data_dir() const { + return std::visit([](auto &&arg) { return arg.site_data_dir(); }, + this->value); + } + + std::string user_config_dir() const { + return std::visit([](auto &&arg) { return arg.user_config_dir(); }, + this->value); + } + + std::string site_config_dir() const { + return std::visit([](auto &&arg) { return arg.site_config_dir(); }, + this->value); + } + + std::string user_cache_dir() const { + return std::visit([](auto &&arg) { return arg.user_cache_dir(); }, + this->value); + } + + std::string site_cache_dir() const { + return std::visit([](auto &&arg) { return arg.site_cache_dir(); }, + this->value); + } + + std::string user_state_dir() const { + return std::visit([](auto &&arg) { return arg.user_state_dir(); }, + this->value); + } + + std::string user_log_dir() const { + return std::visit([](auto &&arg) { return arg.user_log_dir(); }, + this->value); + } + + std::string user_documents_dir() const { + return std::visit([](auto &&arg) { return arg.user_documents_dir(); }, + this->value); + } + + std::string user_downloads_dir() const { + return std::visit([](auto &&arg) { return arg.user_downloads_dir(); }, + this->value); + } + + std::string user_pictures_dir() const { + return std::visit([](auto &&arg) { return arg.user_pictures_dir(); }, + this->value); + } + + std::string user_videos_dir() const { + return std::visit([](auto &&arg) { return arg.user_videos_dir(); }, + this->value); + } + + std::string user_music_dir() const { + return std::visit([](auto &&arg) { return arg.user_music_dir(); }, + this->value); + } + + std::string user_desktop_dir() const { + return std::visit([](auto &&arg) { return arg.user_desktop_dir(); }, + this->value); + } + + std::string user_runtime_dir() const { + return std::visit([](auto &&arg) { return arg.user_runtime_dir(); }, + this->value); + } + + std::string site_runtime_dir() const { + return std::visit([](auto &&arg) { return arg.site_runtime_dir(); }, + this->value); + } + + std::filesystem::path user_data_path() const { + return std::visit([](auto &&arg) { return arg.user_data_path(); }, + this->value); + } + + std::filesystem::path site_data_path() const { + return std::visit([](auto &&arg) { return arg.site_data_path(); }, + this->value); + } + + std::filesystem::path user_config_path() const { + return std::visit([](auto &&arg) { return arg.user_config_path(); }, + this->value); + } + + std::filesystem::path site_config_path() const { + return std::visit([](auto &&arg) { return arg.site_config_path(); }, + this->value); + } + + std::filesystem::path user_cache_path() const { + return std::visit([](auto &&arg) { return arg.user_cache_path(); }, + this->value); + } + + std::filesystem::path site_cache_path() const { + return std::visit([](auto &&arg) { return arg.site_cache_path(); }, + this->value); + } + + std::filesystem::path user_state_path() const { + return std::visit([](auto &&arg) { return arg.user_state_path(); }, + this->value); + } + + std::filesystem::path user_log_path() const { + return std::visit([](auto &&arg) { return arg.user_log_path(); }, + this->value); + } + + std::filesystem::path user_documents_path() const { + return std::visit([](auto &&arg) { return arg.user_documents_path(); }, + this->value); + } + + std::filesystem::path user_downloads_path() const { + return std::visit([](auto &&arg) { return arg.user_downloads_path(); }, + this->value); + } + + std::filesystem::path user_pictures_path() const { + return std::visit([](auto &&arg) { return arg.user_pictures_path(); }, + this->value); + } + + std::filesystem::path user_videos_path() const { + return std::visit([](auto &&arg) { return arg.user_videos_path(); }, + this->value); + } + + std::filesystem::path user_music_path() const { + return std::visit([](auto &&arg) { return arg.user_music_path(); }, + this->value); + } + + std::filesystem::path user_desktop_path() const { + return std::visit([](auto &&arg) { return arg.user_desktop_path(); }, + this->value); + } + + std::filesystem::path user_runtime_path() const { + return std::visit([](auto &&arg) { return arg.user_runtime_path(); }, + this->value); + } + + std::filesystem::path site_runtime_path() const { + return std::visit([](auto &&arg) { return arg.site_runtime_path(); }, + this->value); + } +}; +#else +/** Alias the current concrete implementation chosen at compile-time. */ +using platform_dirs = +#if __APPLE__ platformdirs::macos::macos; #elif _WIN32 platformdirs::windows::windows; #else platformdirs::unix::unix; #endif +#endif using app_dirs = platform_dirs; +using platform_dirs_abc = platformdirs::api::platform_dirs_abc; + /** * @param appname See platform_dirs_abc::appname * @param appauthor See platform_dirs_abc::appauthor @@ -42,7 +250,12 @@ using app_dirs = platform_dirs; * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns data directory tied to the user */ -std::string user_data_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool roaming = false, bool ensure_exists = false); +std::string +user_data_dir(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); /** * @param appname See platform_dirs_abc::appname @@ -52,7 +265,12 @@ std::string user_data_dir(const std::optional& appname = std::nullo * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns data directory shared by users */ -std::string site_data_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool multipath = false, bool ensure_exists = false); +std::string +site_data_dir(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); /** * @param appname See platform_dirs_abc::appname @@ -62,7 +280,12 @@ std::string site_data_dir(const std::optional& appname = std::nullo * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns config directory tied to the user */ -std::string user_config_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool roaming = false, bool ensure_exists = false); +std::string user_config_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); /** * @param appname See platform_dirs_abc::appname @@ -72,7 +295,12 @@ std::string user_config_dir(const std::optional& appname = std::nul * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns config directory shared by users */ -std::string site_config_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool multipath = false, bool ensure_exists = false); +std::string site_config_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); /** * @param appname See platform_dirs_abc::appname @@ -82,7 +310,12 @@ std::string site_config_dir(const std::optional& appname = std::nul * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns cache directory tied to the user */ -std::string user_cache_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool roaming = false, bool ensure_exists = false); +std::string user_cache_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); /** * @param appname See platform_dirs_abc::appname @@ -92,18 +325,257 @@ std::string user_cache_dir(const std::optional& appname = std::null * @param ensure_exists See platform_dirs_abc::ensure_exists * @returns cache directory shared by users */ -std::string site_cache_dir(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool multipath = false, bool ensure_exists = false); +std::string site_cache_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns state directory tied to the user + */ +std::string user_state_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns log directory tied to the user + */ +std::string +user_log_dir(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** @returns documents directory tied to the user */ std::string user_documents_dir(); +/** @returns downloads directory tied to the user */ std::string user_downloads_dir(); +/** @returns pictures directory tied to the user */ std::string user_pictures_dir(); -std::filesystem::path user_data_path(); +/** @returns videos directory tied to the user */ +std::string user_videos_dir(); + +/** @returns music directory tied to the user */ +std::string user_music_dir(); + +/** @returns desktop directory tied to the user */ +std::string user_desktop_dir(); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns runtime directory tied to the user + */ +std::string user_runtime_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param multipath See platform_dirs_abc::multipath + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns runtime directory shared by users + */ +std::string site_runtime_dir( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns data path tied to the user + */ +std::filesystem::path user_data_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param multipath See platform_dirs_abc::multipath + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns data directory shared by users + */ +std::filesystem::path site_data_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns config path tied to the user + */ +std::filesystem::path user_config_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param multipath See platform_dirs_abc::multipath + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns config directory shared by users + */ +std::filesystem::path site_config_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns cache path tied to the user + */ +std::filesystem::path user_cache_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param multipath See platform_dirs_abc::multipath + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns cache directory shared by users + */ +std::filesystem::path site_cache_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns state path tied to the user + */ +std::filesystem::path user_state_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns log path tied to the user + */ +std::filesystem::path +user_log_path(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** @returns documents path tied to the user */ std::filesystem::path user_documents_path(); +/** @returns downloads path tied to the user */ std::filesystem::path user_downloads_path(); +/** @returns pictures path tied to the user */ +std::filesystem::path user_pictures_path(); + +/** @returns videos path tied to the user */ +std::filesystem::path user_videos_path(); + +/** @returns music path tied to the user */ +std::filesystem::path user_music_path(); + +/** @returns desktop path tied to the user */ +std::filesystem::path user_desktop_path(); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param roaming See platform_dirs_abc::roaming + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns runtime path tied to the user + */ +std::filesystem::path user_runtime_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool ensure_exists = false); + +/** + * @param appname See platform_dirs_abc::appname + * @param appauthor See platform_dirs_abc::appauthor + * @param version See platform_dirs_abc::version + * @param multipath See platform_dirs_abc::multipath + * @param ensure_exists See platform_dirs_abc::ensure_exists + * @returns runtime directory shared by users + */ +std::filesystem::path site_runtime_path( + const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool multipath = false, bool ensure_exists = false); + } // namespace platformdirs diff --git a/include/platformdirs/api.h b/include/platformdirs/api.h index 4a7a093..d965db2 100644 --- a/include/platformdirs/api.h +++ b/include/platformdirs/api.h @@ -1,8 +1,8 @@ #pragma once #include +#include #include #include -#include #include namespace platformdirs { @@ -10,86 +10,90 @@ namespace api { class platform_dirs_abc { public: -std::optional appname; -std::variant appauthor; -std::optional version; -bool roaming; -bool multipath; -bool opinion; -bool ensure_exists; - -platform_dirs_abc(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool roaming = false, bool multipath = false, bool opinion = true, bool ensure_exists = false); + std::optional appname; + std::variant appauthor; + std::optional version; + bool roaming; + bool multipath; + bool opinion; + bool ensure_exists; + + platform_dirs_abc(const std::optional &appname = std::nullopt, + const std::variant + &appauthor = std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool multipath = false, + bool opinion = true, bool ensure_exists = false); protected: -auto append_app_name_and_version(const std::vector& base) const -> std::string; -auto optionally_create_directory(const std::string& path) const -> void; + auto append_app_name_and_version(const std::vector &base) const + -> std::string; + auto optionally_create_directory(const std::string &path) const -> void; public: + virtual std::string user_data_dir() const = 0; -virtual std::string user_data_dir() const = 0; - -virtual std::string site_data_dir() const = 0; - -// virtual std::string user_config_dir() const = 0; + virtual std::string site_data_dir() const = 0; -// virtual std::string site_config_dir() const = 0; + virtual std::string user_config_dir() const = 0; -// virtual std::string user_cache_dir() const = 0; + virtual std::string site_config_dir() const = 0; -// virtual std::string site_cache_dir() const = 0; + virtual std::string user_cache_dir() const = 0; -// virtual std::string user_state_dir() const = 0; + virtual std::string site_cache_dir() const = 0; -// virtual std::string user_log_dir() const = 0; + virtual std::string user_state_dir() const = 0; -// virtual std::string user_documents_dir() const = 0; + virtual std::string user_log_dir() const = 0; -// virtual std::string user_downloads_dir() const = 0; + virtual std::string user_documents_dir() const = 0; -// virtual std::string user_pictures_dir() const = 0; + virtual std::string user_downloads_dir() const = 0; -// virtual std::string user_videos_dir() const = 0; + virtual std::string user_pictures_dir() const = 0; -// virtual std::string user_music_dir() const = 0; + virtual std::string user_videos_dir() const = 0; -// virtual std::string user_desktop_dir() const = 0; + virtual std::string user_music_dir() const = 0; -// virtual std::string user_runtime_dir() const = 0; + virtual std::string user_desktop_dir() const = 0; -// virtual std::string site_runtime_dir() const = 0; + virtual std::string user_runtime_dir() const = 0; -std::filesystem::path user_data_path() const; + virtual std::string site_runtime_dir() const = 0; -std::filesystem::path site_data_path() const; + virtual std::filesystem::path user_data_path() const; -// virtual std::filesystem::path user_config_path() const; + virtual std::filesystem::path site_data_path() const; -// virtual std::filesystem::path site_config_path() const; + virtual std::filesystem::path user_config_path() const; -// virtual std::filesystem::path user_cache_path() const; + virtual std::filesystem::path site_config_path() const; -// virtual std::filesystem::path site_cache_path() const; + virtual std::filesystem::path user_cache_path() const; -// virtual std::filesystem::path user_state_path() const; + virtual std::filesystem::path site_cache_path() const; -// virtual std::filesystem::path user_log_path() const; + virtual std::filesystem::path user_state_path() const; -// virtual std::filesystem::path user_documents_path() const; + virtual std::filesystem::path user_log_path() const; -// virtual std::filesystem::path user_downloads_path() const; + virtual std::filesystem::path user_documents_path() const; -// virtual std::filesystem::path user_pictures_path() const; + virtual std::filesystem::path user_downloads_path() const; -// virtual std::filesystem::path user_videos_path() const; + virtual std::filesystem::path user_pictures_path() const; -// virtual std::filesystem::path user_music_path() const; + virtual std::filesystem::path user_videos_path() const; -// virtual std::filesystem::path user_desktop_path() const; + virtual std::filesystem::path user_music_path() const; -// virtual std::filesystem::path user_runtime_path() const; + virtual std::filesystem::path user_desktop_path() const; -// virtual std::filesystem::path site_runtime_path() const; + virtual std::filesystem::path user_runtime_path() const; + virtual std::filesystem::path site_runtime_path() const; }; } // namespace api diff --git a/include/platformdirs/cosmopolitan.h b/include/platformdirs/cosmopolitan.h deleted file mode 100644 index 0069387..0000000 --- a/include/platformdirs/cosmopolitan.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "api.h" - -namespace platformdirs { -namespace cosmopolitan { - -class cosmopolitan : public platformdirs::api::platform_dirs_abc { - - - -} - -} // namespace cosmopolitan -} // namespace platformdirs diff --git a/include/platformdirs/macos.h b/include/platformdirs/macos.h index 6f70f09..b941d0f 100644 --- a/include/platformdirs/macos.h +++ b/include/platformdirs/macos.h @@ -1 +1,54 @@ #pragma once +#include "api.h" +#include +#include +#include +#include + +namespace platformdirs { +namespace macos { + +class macos : public platformdirs::api::platform_dirs_abc { +public: + macos(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool multipath = false, bool opinion = true, + bool ensure_exists = false); + + std::string user_data_dir() const override; + + std::string site_data_dir() const override; + + std::string user_config_dir() const override; + + std::string site_config_dir() const override; + + std::string user_cache_dir() const override; + + std::string site_cache_dir() const override; + + std::string user_state_dir() const override; + + std::string user_log_dir() const override; + + std::string user_documents_dir() const override; + + std::string user_downloads_dir() const override; + + std::string user_pictures_dir() const override; + + std::string user_videos_dir() const override; + + std::string user_music_dir() const override; + + std::string user_desktop_dir() const override; + + std::string user_runtime_dir() const override; + + std::string site_runtime_dir() const override; +}; + +} // namespace macos +} // namespace platformdirs diff --git a/include/platformdirs/unix.h b/include/platformdirs/unix.h index a5d1a46..36de9b6 100644 --- a/include/platformdirs/unix.h +++ b/include/platformdirs/unix.h @@ -1,54 +1,100 @@ #pragma once #undef unix -#include +#include "api.h" #include #include +#include #include -#include "api.h" namespace platformdirs { namespace unix { +/** + * On Unix/Linux, we follow the XDG Basedir Spec + * https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html. + * + * The spec allows overriding directories with environment variables. The + * examples shown are the default values, alongside the name of the environment + * variable that overrides them. Makes use of the appname, version, multipath, + * opinion, ensure_exists. + */ class unix : public platformdirs::api::platform_dirs_abc { public: + unix(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool multipath = false, bool opinion = true, + bool ensure_exists = false); + + /** @return data directory tied to the user, e.g. + * `~/.local/share/$appname/$version` or `$XDG_DATA_HOME/$appname/$version` */ + std::string user_data_dir() const override; + +private: + auto site_data_dirs() const -> std::vector; + +public: + /** + * @returns data directories shared by users (if multipath is + * enabled and `XDG_DATA_DIRS` is set and a multi path the response is also a + * multi path separated by the OS path separator), e.g. + * `/usr/local/share/$appname/$version` or `/usr/share/$appname/$version` + */ + std::string site_data_dir() const override; + + /** @return config directory tied to the user, e.g. + * `~/.config/$appname/$version` or `$XDG_CONFIG_HOME/$appname/$version` */ + std::string user_config_dir() const override; -unix(const std::optional& appname = std::nullopt, const std::variant& appauthor = std::nullopt, const std::optional& version = std::nullopt, bool roaming = false, bool multipath = false, bool opinion = true, bool ensure_exists = false); +private: + auto site_config_dirs() const -> std::vector; -std::string user_data_dir() const override; +public: + /** @return config directories shared by users (if multipath + * is enabled and `XDG_CONFIG_DIRS` is set and a multi path the response is + * also a multi path separated by the OS path separator), e.g. + * `/etc/xdg/$appname/$version` */ + std::string site_config_dir() const override; -std::string site_data_dir() const override; + /** @return cache directory tied to the user, e.g. + * `~/.cache/$appname/$version` or + * `~/$XDG_CACHE_HOME/$appname/$version` */ + std::string user_cache_dir() const override; -// virtual std::string user_config_dir() const; + /** @return cache directory shared by users, e.g. + * `/var/cache/$appname/$version` */ + std::string site_cache_dir() const override; -// virtual std::string site_config_dir() const; + std::string user_state_dir() const override; -// virtual std::string user_cache_dir() const; + std::string user_log_dir() const override; -// virtual std::string site_cache_dir() const; + std::string user_documents_dir() const override; -// virtual std::string user_state_dir() const; + std::string user_downloads_dir() const override; -// virtual std::string user_log_dir() const; + std::string user_pictures_dir() const override; -// virtual std::string user_documents_dir() const; + std::string user_videos_dir() const override; -// virtual std::string user_downloads_dir() const; + std::string user_music_dir() const override; -// virtual std::string user_pictures_dir() const; + std::string user_desktop_dir() const override; -// virtual std::string user_videos_dir() const; + std::string user_runtime_dir() const override; -// virtual std::string user_music_dir() const; + std::string site_runtime_dir() const override; -// virtual std::string user_desktop_dir() const; + std::filesystem::path site_data_path() const override; -// virtual std::string user_runtime_dir() const; + std::filesystem::path site_config_path() const override; -// virtual std::string site_runtime_dir() const; + std::filesystem::path site_cache_path() const override; private: -auto site_data_dirs() const -> std::vector; - + std::filesystem::path + first_item_as_path_if_multipath(const std::string &directory) const; }; } // namespace unix diff --git a/include/platformdirs/version.h b/include/platformdirs/version.h index 7b1fb7b..aae1209 100644 --- a/include/platformdirs/version.h +++ b/include/platformdirs/version.h @@ -1,7 +1,7 @@ #pragma once -#include -#include #include +#include +#include namespace platformdirs { namespace version { diff --git a/include/platformdirs/windows.h b/include/platformdirs/windows.h index 6f70f09..bb4ed3a 100644 --- a/include/platformdirs/windows.h +++ b/include/platformdirs/windows.h @@ -1 +1,64 @@ #pragma once +#include "api.h" +#include +#include +#include +#include + +namespace platformdirs { +namespace windows { + +class windows : public platformdirs::api::platform_dirs_abc { +public: + windows(const std::optional &appname = std::nullopt, + const std::variant &appauthor = + std::nullopt, + const std::optional &version = std::nullopt, + bool roaming = false, bool multipath = false, bool opinion = true, + bool ensure_exists = false); + + std::string user_data_dir() const override; + +private: + struct append_parts_options { + std::optional opinion_value; + }; + std::string append_parts( + const std::string &path, + const platformdirs::windows::windows::append_parts_options &options = {}) + const; + +public: + std::string site_data_dir() const override; + + std::string user_config_dir() const override; + + std::string site_config_dir() const override; + + std::string user_cache_dir() const override; + + std::string site_cache_dir() const override; + + std::string user_state_dir() const override; + + std::string user_log_dir() const override; + + std::string user_documents_dir() const override; + + std::string user_downloads_dir() const override; + + std::string user_pictures_dir() const override; + + std::string user_videos_dir() const override; + + std::string user_music_dir() const override; + + std::string user_desktop_dir() const override; + + std::string user_runtime_dir() const override; + + std::string site_runtime_dir() const override; +}; + +} // namespace windows +} // namespace platformdirs diff --git a/src/platformdirs.cpp b/src/platformdirs.cpp index 5224225..473414c 100644 --- a/src/platformdirs.cpp +++ b/src/platformdirs.cpp @@ -1,12 +1,254 @@ +#undef unix #include "platformdirs.h" #include -#include #include +#include +#include + +std::string platformdirs::user_data_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_data_dir(); +} + +std::string platformdirs::site_data_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_data_dir(); +} + +std::string platformdirs::user_config_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_config_dir(); +} + +std::string platformdirs::site_config_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_config_dir(); +} + +std::string platformdirs::user_cache_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_cache_dir(); +} + +std::string platformdirs::site_cache_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_cache_dir(); +} + +std::string platformdirs::user_state_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_state_dir(); +} + +std::string platformdirs::user_log_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_log_dir(); +} + +std::string platformdirs::user_documents_dir() { + return platformdirs::platform_dirs().user_documents_dir(); +} + +std::string platformdirs::user_downloads_dir() { + return platformdirs::platform_dirs().user_downloads_dir(); +} + +std::string platformdirs::user_pictures_dir() { + return platformdirs::platform_dirs().user_pictures_dir(); +} + +std::string platformdirs::user_videos_dir() { + return platformdirs::platform_dirs().user_videos_dir(); +} + +std::string platformdirs::user_music_dir() { + return platformdirs::platform_dirs().user_music_dir(); +} + +std::string platformdirs::user_desktop_dir() { + return platformdirs::platform_dirs().user_desktop_dir(); +} + +std::string platformdirs::user_runtime_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_runtime_dir(); +} + +std::string platformdirs::site_runtime_dir( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_runtime_dir(); +} + +std::filesystem::path platformdirs::user_data_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_data_path(); +} + +std::filesystem::path platformdirs::site_data_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_data_path(); +} + +std::filesystem::path platformdirs::user_config_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_config_path(); +} + +std::filesystem::path platformdirs::site_config_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_config_path(); +} + +std::filesystem::path platformdirs::user_cache_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_cache_path(); +} + +std::filesystem::path platformdirs::site_cache_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_cache_path(); +} + +std::filesystem::path platformdirs::user_state_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_state_path(); +} + +std::filesystem::path platformdirs::user_log_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_log_path(); +} + +std::filesystem::path platformdirs::user_documents_path() { + return platformdirs::platform_dirs().user_documents_path(); +} + +std::filesystem::path platformdirs::user_downloads_path() { + return platformdirs::platform_dirs().user_downloads_path(); +} + +std::filesystem::path platformdirs::user_pictures_path() { + return platformdirs::platform_dirs().user_pictures_path(); +} + +std::filesystem::path platformdirs::user_videos_path() { + return platformdirs::platform_dirs().user_videos_path(); +} + +std::filesystem::path platformdirs::user_music_path() { + return platformdirs::platform_dirs().user_music_path(); +} + +std::filesystem::path platformdirs::user_desktop_path() { + return platformdirs::platform_dirs().user_desktop_path(); +} -std::string platformdirs::user_data_dir(const std::optional& appname, const std::variant& appauthor, const std::optional& version, bool roaming, bool ensure_exists) { - return platformdirs::api::platform_dirs(appname, appauthor, version, roaming, false, true, ensure_exists).user_data_dir(); +std::filesystem::path platformdirs::user_runtime_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, roaming, + false, true, ensure_exists) + .user_runtime_path(); } -std::string platformdirs::site_data_dir(const std::optional& appname, const std::variant& appauthor, const std::optional& version, bool multipath, bool ensure_exists) { - return platformdirs::api::platform_dirs(appname, appauthor, version, false, multipath, true, ensure_exists).user_data_dir(); +std::filesystem::path platformdirs::site_runtime_path( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool multipath, + bool ensure_exists) { + return platformdirs::platform_dirs(appname, appauthor, version, false, + multipath, true, ensure_exists) + .site_runtime_path(); } diff --git a/src/platformdirs.h b/src/platformdirs.h index f9111ef..9accb1e 100644 --- a/src/platformdirs.h +++ b/src/platformdirs.h @@ -1,2 +1,3 @@ #pragma once +#undef unix #include diff --git a/src/platformdirs/api.cpp b/src/platformdirs/api.cpp index 6529229..1e480c9 100644 --- a/src/platformdirs/api.cpp +++ b/src/platformdirs/api.cpp @@ -1,108 +1,128 @@ #include "api.h" +#include +#include #include -#include #include +#include #include #include #include #include -#include -#include -#include -platformdirs::api::platform_dirs_abc::platform_dirs_abc(const std::optional& appname, const std::variant& appauthor, const std::optional& version, bool roaming, bool multipath, bool opinion, bool ensure_exists) { - this->appname = appname; - this->appauthor = appauthor; - this->version = version; - this->roaming = roaming; - this->multipath = multipath; - this->opinion = opinion; - this->ensure_exists = ensure_exists; +platformdirs::api::platform_dirs_abc::platform_dirs_abc( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, bool multipath, + bool opinion, bool ensure_exists) { + this->appname = appname; + this->appauthor = appauthor; + this->version = version; + this->roaming = roaming; + this->multipath = multipath; + this->opinion = opinion; + this->ensure_exists = ensure_exists; } -std::filesystem::path platformdirs::api::platform_dirs_abc::user_data_path() const { - return std::filesystem::path(this->user_data_dir()); +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_data_path() const { + return std::filesystem::path(this->user_data_dir()); } -std::filesystem::path platformdirs::api::platform_dirs_abc::site_data_path() const { - return std::filesystem::path(this->site_data_dir()); +std::filesystem::path +platformdirs::api::platform_dirs_abc::site_data_path() const { + return std::filesystem::path(this->site_data_dir()); } -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_config_path() const { -// return std::filesystem::path(this->user_config_dir()); -// } - -// std::filesystem::path platformdirs::api::platform_dirs_abc::site_config_path() const { -// return std::filesystem::path(this->site_config_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_config_path() const { + return std::filesystem::path(this->user_config_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_cache_path() const { -// return std::filesystem::path(this->user_cache_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::site_config_path() const { + return std::filesystem::path(this->site_config_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::site_cache_path() const { -// return std::filesystem::path(this->site_cache_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_cache_path() const { + return std::filesystem::path(this->user_cache_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_state_path() const { -// return std::filesystem::path(this->user_state_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::site_cache_path() const { + return std::filesystem::path(this->site_cache_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_log_path() const { -// return std::filesystem::path(this->user_log_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_state_path() const { + return std::filesystem::path(this->user_state_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_documents_path() const { -// return std::filesystem::path(this->user_documents_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_log_path() const { + return std::filesystem::path(this->user_log_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_downloads_path() const { -// return std::filesystem::path(this->user_downloads_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_documents_path() const { + return std::filesystem::path(this->user_documents_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_pictures_path() const { -// return std::filesystem::path(this->user_pictures_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_downloads_path() const { + return std::filesystem::path(this->user_downloads_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_videos_path() const { -// return std::filesystem::path(this->user_videos_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_pictures_path() const { + return std::filesystem::path(this->user_pictures_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_music_path() const { -// return std::filesystem::path(this->user_music_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_videos_path() const { + return std::filesystem::path(this->user_videos_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_desktop_path() const { -// return std::filesystem::path(this->user_desktop_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_music_path() const { + return std::filesystem::path(this->user_music_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::user_runtime_path() const { -// return std::filesystem::path(this->user_runtime_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_desktop_path() const { + return std::filesystem::path(this->user_desktop_dir()); +} -// std::filesystem::path platformdirs::api::platform_dirs_abc::site_runtime_path() const { -// return std::filesystem::path(this->site_runtime_dir()); -// } +std::filesystem::path +platformdirs::api::platform_dirs_abc::user_runtime_path() const { + return std::filesystem::path(this->user_runtime_dir()); +} -auto platformdirs::api::platform_dirs_abc::append_app_name_and_version(const std::vector& base) const -> std::string { - auto params = std::vector(base.cbegin() + 1, base.cend()); - if (this->appname) { - params.push_back(this->appname.value()); - if (this->version) { - params.push_back(this->version.value()); - } - } - auto path = std::filesystem::path(base.at(0)); - for (auto p : params) { - path = path / p; - } - this->optionally_create_directory(path.string()); - return path.string(); +std::filesystem::path +platformdirs::api::platform_dirs_abc::site_runtime_path() const { + return std::filesystem::path(this->site_runtime_dir()); } -auto platformdirs::api::platform_dirs_abc::optionally_create_directory(const std::string& path) const -> void { - if (this->ensure_exists) { - std::filesystem::create_directories(path); +auto platformdirs::api::platform_dirs_abc::append_app_name_and_version( + const std::vector &base) const -> std::string { + auto params = std::vector(base.cbegin() + 1, base.cend()); + if (this->appname) { + params.push_back(this->appname.value()); + if (this->version) { + params.push_back(this->version.value()); } + } + auto path = std::filesystem::path(base.at(0)); + for (auto p : params) { + path = path / p; + } + this->optionally_create_directory(path.string()); + return path.string(); } +auto platformdirs::api::platform_dirs_abc::optionally_create_directory( + const std::string &path) const -> void { + if (this->ensure_exists) { + std::filesystem::create_directories(path); + } +} diff --git a/src/platformdirs/cosmopolitan.cpp b/src/platformdirs/cosmopolitan.cpp deleted file mode 100644 index 58fe1bd..0000000 --- a/src/platformdirs/cosmopolitan.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include "utils.h" - -namespace platformdirs { -namespace cosmopolitan { - -class cosmopolitan : platform_dirs_abc { - -public: - virtual std::string user_data_dir() { - if (IsWindows()) { - - } else if (IsXnu()) { - - } else { - auto path = std::string(std::getenv("XDG_DATA_HOME")); - platformdirs::utils::ltrim(path); - platformdirs::utils::rtrim(path); - if (path == "") { - const auto home = std::filesystem::path(std::getenv("HOME")); - if (home == "") { - throw std::runtime_error("HOME not set"); - } - path = (home / ".local/share").string(); - } - return this->append_app_name_and_version(path); - } - } - - // snip -} - -} // namespace cosmopolitan -} // namespace platformdirs diff --git a/src/platformdirs/cosmopolitan.h b/src/platformdirs/cosmopolitan.h deleted file mode 100644 index 31ba2df..0000000 --- a/src/platformdirs/cosmopolitan.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include +#include +#include +#include +#include + +platformdirs::macos::macos::macos( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, bool multipath, + bool opinion, bool ensure_exists) + : platformdirs::api::platform_dirs_abc(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists) {} + +auto platformdirs::macos::macos::user_data_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Library/Application Support") + .string()}); +} + +auto platformdirs::macos::macos::site_data_dir() const -> std::string { + return "/Library/Application Support"; +} + +auto platformdirs::macos::macos::user_config_dir() const -> std::string { + return this->user_data_dir(); +} + +auto platformdirs::macos::macos::site_config_dir() const -> std::string { + return this->site_data_dir(); +} + +auto platformdirs::macos::macos::user_cache_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Library/Caches").string()}); +} + +auto platformdirs::macos::macos::site_cache_dir() const -> std::string { + return "/Library/Caches"; +} + +auto platformdirs::macos::macos::user_state_dir() const -> std::string { + return this->user_data_dir(); +} + +auto platformdirs::macos::macos::user_log_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Library/Logs").string()}); +} + +auto platformdirs::macos::macos::user_documents_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Documents").string()}); +} + +auto platformdirs::macos::macos::user_downloads_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Downloads").string()}); +} + +auto platformdirs::macos::macos::user_pictures_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Pictures").string()}); +} + +auto platformdirs::macos::macos::user_videos_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Movies").string()}); +} + +auto platformdirs::macos::macos::user_music_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Music").string()}); +} + +auto platformdirs::macos::macos::user_desktop_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Desktop").string()}); +} + +auto platformdirs::macos::macos::user_runtime_dir() const -> std::string { + return this->append_app_name_and_version( + {(platformdirs::utils::home_path() / "Library/Caches/TemporaryItems") + .string()}); +} + +auto platformdirs::macos::macos::site_runtime_dir() const -> std::string { + return this->user_runtime_dir(); +} diff --git a/src/platformdirs/macos.h b/src/platformdirs/macos.h new file mode 100644 index 0000000..dee9cde --- /dev/null +++ b/src/platformdirs/macos.h @@ -0,0 +1,2 @@ +#pragma once +#include \ No newline at end of file diff --git a/src/platformdirs/unix.cpp b/src/platformdirs/unix.cpp index 5599424..ce66d40 100644 --- a/src/platformdirs/unix.cpp +++ b/src/platformdirs/unix.cpp @@ -1,44 +1,265 @@ #undef unix #include "unix.h" -#include +#include #include #include +#include #include -#include +#if !_WIN32 +#include +#endif +#if __COSMOPOLITAN__ +#include +#endif #include "utils.h" -platformdirs::unix::unix::unix(const std::optional& appname, const std::variant& appauthor, const std::optional& version, bool roaming, bool multipath, bool opinion, bool ensure_exists) : platformdirs::api::platform_dirs_abc(appname, appauthor, version, roaming, multipath, opinion, ensure_exists) { } +platformdirs::unix::unix::unix( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, bool multipath, + bool opinion, bool ensure_exists) + : platformdirs::api::platform_dirs_abc(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists) {} std::string platformdirs::unix::unix::user_data_dir() const { - auto path_c_str = std::getenv("XDG_DATA_HOME"); - auto path = path_c_str ? std::string(path_c_str) : std::string(); - platformdirs::utils::ltrim(path); - platformdirs::utils::rtrim(path); - if (path == "") { - path = (platformdirs::utils::home_path() / ".local/share").string(); - } - return this->append_app_name_and_version({path}); + auto path_c_str = std::getenv("XDG_DATA_HOME"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = (platformdirs::utils::home_path() / ".local/share").string(); + } + return this->append_app_name_and_version({path}); +} + +auto platformdirs::unix::unix::site_data_dirs() const + -> std::vector { + auto path_c_str = std::getenv("XDG_DATA_DIRS"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = std::string("/usr/local/share") + platformdirs::utils::pathsep() + + "/usr/share"; + } + auto appended = std::vector(); + for (auto p : + platformdirs::utils::split(path, platformdirs::utils::pathsep())) { + appended.push_back(this->append_app_name_and_version({p})); + } + return appended; +} + +std::string platformdirs::unix::unix::site_data_dir() const { + auto const dirs = this->site_data_dirs(); + if (!this->multipath) { + return dirs.at(0); + } + return platformdirs::utils::join(dirs, platformdirs::utils::pathsep()); +} + +auto platformdirs::unix::unix::user_config_dir() const -> std::string { + auto path_c_str = std::getenv("XDG_CONFIG_HOME"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = (platformdirs::utils::home_path() / ".config").string(); + } + return this->append_app_name_and_version({path}); +} + +auto platformdirs::unix::unix::site_config_dirs() const + -> std::vector { + auto path_c_str = std::getenv("XDG_CONFIG_DIRS"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = "/etc/xdg"; + } + auto appended = std::vector(); + for (auto p : + platformdirs::utils::split(path, platformdirs::utils::pathsep())) { + appended.push_back(this->append_app_name_and_version({p})); + } + return appended; +} + +std::string platformdirs::unix::unix::site_config_dir() const { + auto const dirs = this->site_config_dirs(); + if (!this->multipath) { + return dirs.at(0); + } + return platformdirs::utils::join(dirs, platformdirs::utils::pathsep()); +} + +auto platformdirs::unix::unix::user_cache_dir() const -> std::string { + auto path_c_str = std::getenv("XDG_CACHE_HOME"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = (platformdirs::utils::home_path() / ".cache").string(); + } + return this->append_app_name_and_version({path}); +} + +std::string platformdirs::unix::unix::site_cache_dir() const { + return this->append_app_name_and_version({"/var/cache"}); +} + +auto platformdirs::unix::unix::user_state_dir() const -> std::string { + auto path_c_str = std::getenv("XDG_STATE_HOME"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { + path = (platformdirs::utils::home_path() / ".local/state").string(); + } + return this->append_app_name_and_version({path}); +} + +auto platformdirs::unix::unix::user_log_dir() const -> std::string { + auto path = this->user_state_dir(); + if (this->opinion) { + path = (std::filesystem::path(path) / "log").string(); + this->optionally_create_directory(path); + } + return path; +} + +auto platformdirs::unix::unix::user_documents_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_DOCUMENTS_DIR", "Documents"); +} + +auto platformdirs::unix::unix::user_downloads_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_DOWNLOAD_DIR", "Downloads"); +} + +auto platformdirs::unix::unix::user_pictures_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_PICTURES_DIR", "Pictures"); +} + +auto platformdirs::unix::unix::user_videos_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_VIDEOS_DIR", "Videos"); } -auto platformdirs::unix::unix::site_data_dirs() const -> std::vector { - auto path_c_str = std::getenv("XDG_DATA_DIRS"); - auto path = path_c_str ? std::string(path_c_str) : std::string(); - platformdirs::utils::ltrim(path); - platformdirs::utils::rtrim(path); - if (path == "") { - path = std::string("/usr/local/share") + platformdirs::utils::pathsep() + "/usr/share"; +auto platformdirs::unix::unix::user_music_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_MUSIC_DIR", "Music"); +} + +auto platformdirs::unix::unix::user_desktop_dir() const -> std::string { + return platformdirs::unix::get_user_media("XDG_DESKTOP_DIR", "Desktop"); +} + +auto platformdirs::unix::unix::user_runtime_dir() const -> std::string { + auto path_c_str = std::getenv("XDG_RUNTIME_DIR"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { +#if __COSMOPOLITAN__ + if (IsFreebsd()) { + path = (std::filesystem::path("/var/run/user") / std::to_string(getuid())) + .string(); + if (!std::filesystem::exists(path)) { + path = std::string("/tmp/runtime-") + std::to_string(getuid()); + } + } else { + path = std::string("/run/user/") + std::to_string(getuid()); } - auto appended = std::vector(); - for (auto p : platformdirs::utils::split(path, platformdirs::utils::pathsep())) { - appended.push_back(this->append_app_name_and_version({p})); +#elif BSD + path = (std::filesystem::path("/var/run/user") / std::to_string(getuid())) + .string(); + if (!std::filesystem::exists(path)) { + path = std::string("/tmp/runtime-") + std::to_string(getuid()); } - return appended; +#elif _WIN32 + throw std::runtime_error( + "getuid() equivalent for windows not implemented yet"); +#else + path = std::string("/run/user/") + std::to_string(getuid()); +#endif + } + return this->append_app_name_and_version({path}); } -std::string platformdirs::unix::unix::site_data_dir() const { - auto const dirs = this->site_data_dirs(); - if (!this->multipath) { - return dirs.at(0); +auto platformdirs::unix::unix::site_runtime_dir() const -> std::string { + auto path_c_str = std::getenv("XDG_RUNTIME_DIR"); + auto path = path_c_str ? std::string(path_c_str) : std::string(); + platformdirs::utils::ltrim(path); + platformdirs::utils::rtrim(path); + if (path == "") { +#if __COSMOPOLITAN__ + if (IsFreebsd()) { + path = "/var/run"; + } else { + path = "/run"; } - return platformdirs::utils::join(dirs, platformdirs::utils::pathsep()); +#elif BSD + path = "/var/run"; +#else + path = "/run"; +#endif + } + return this->append_app_name_and_version({path}); +} + +auto platformdirs::unix::unix::site_data_path() const -> std::filesystem::path { + return this->first_item_as_path_if_multipath(this->site_data_dir()); +} + +auto platformdirs::unix::unix::site_config_path() const + -> std::filesystem::path { + return this->first_item_as_path_if_multipath(this->site_config_dir()); +} + +auto platformdirs::unix::unix::site_cache_path() const + -> std::filesystem::path { + return this->first_item_as_path_if_multipath(this->site_cache_dir()); +} + +std::filesystem::path platformdirs::unix::unix::first_item_as_path_if_multipath( + const std::string &directory) const { + std::string dir2; + if (this->multipath) { + dir2 = platformdirs::utils::split(directory, + platformdirs::utils::pathsep())[0]; + } else { + dir2 = directory; + } + return std::filesystem::path(dir2); +} + +auto platformdirs::unix::get_user_media(const std::string &env_var, + const std::string &fallback_tilde_path) + -> std::string { + std::string media_dir; + auto media_dir_opt = platformdirs::unix::get_user_dirs_folder(env_var); + if (media_dir_opt) { + media_dir = media_dir_opt.value(); + } else { + auto media_dir_c_str = std::getenv(env_var.c_str()); + media_dir = media_dir_c_str ? std::string(media_dir_c_str) : std::string(); + platformdirs::utils::ltrim(media_dir); + platformdirs::utils::rtrim(media_dir); + if (media_dir == "") { + media_dir = + (platformdirs::utils::home_path() / fallback_tilde_path).string(); + } + } + return media_dir; +} + +auto platformdirs::unix::get_user_dirs_folder(const std::string &key) + -> std::optional { + auto user_dirs_config_path = + std::filesystem::path(platformdirs::unix::unix().user_config_dir()) / + "user-dirs.dirs"; + if (std::filesystem::exists(user_dirs_config_path)) { + // TODO + return std::nullopt; + } + return std::nullopt; } diff --git a/src/platformdirs/unix.h b/src/platformdirs/unix.h index b20b5cf..cfb1b3c 100644 --- a/src/platformdirs/unix.h +++ b/src/platformdirs/unix.h @@ -1,3 +1,15 @@ #pragma once #undef unix -#include \ No newline at end of file +#include +#include + +namespace platformdirs { +namespace unix { + +auto get_user_media(const std::string &env_var, + const std::string &fallback_tilde_path) -> std::string; + +auto get_user_dirs_folder(const std::string &key) -> std::optional; + +} // namespace unix +} // namespace platformdirs \ No newline at end of file diff --git a/src/platformdirs/utils.h b/src/platformdirs/utils.h index 402afdd..b853709 100644 --- a/src/platformdirs/utils.h +++ b/src/platformdirs/utils.h @@ -1,7 +1,13 @@ -#include -#include +#pragma once +#include #include +#include #include +#include +#include +#if __COSMOPOLITAN__ +#include +#endif namespace platformdirs { namespace utils { @@ -9,86 +15,85 @@ namespace utils { // https://stackoverflow.com/questions/216823/how-to-trim-a-stdstring // trim from start (in place) inline void ltrim(std::string &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); } // https://stackoverflow.com/questions/216823/how-to-trim-a-stdstring // trim from end (in place) inline void rtrim(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); - }).base(), s.end()); + s.erase(std::find_if(s.rbegin(), s.rend(), + [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); } - inline auto home_path() -> std::filesystem::path { #if __COSMOPOLITAN__ - if (IsWindows()) { - if (auto const userprofile_dir = std::getenv("USERPROFILE")) { - return std::filesystem::path(userprofile_dir); - } else { - throw std::runtime_error("%USERPROFILE% not set"); - } - } else { - if (auto const home_dir = std::getenv("HOME")) { - return std::filesystem::path(home_dir); - } else { - throw std::runtime_error("$HOME not set"); - } - } -#elif _WIN32 + if (IsWindows()) { if (auto const userprofile_dir = std::getenv("USERPROFILE")) { - return std::filesystem::path(userprofile_dir); + return std::filesystem::path(userprofile_dir); } else { - throw std::runtime_error("%USERPROFILE% not set"); + throw std::runtime_error("%USERPROFILE% not set"); } -#else + } else { if (auto const home_dir = std::getenv("HOME")) { - return std::filesystem::path(home_dir); + return std::filesystem::path(home_dir); } else { - throw std::runtime_error("$HOME not set"); + throw std::runtime_error("$HOME not set"); } + } +#elif _WIN32 + if (auto const userprofile_dir = std::getenv("USERPROFILE")) { + return std::filesystem::path(userprofile_dir); + } else { + throw std::runtime_error("%USERPROFILE% not set"); + } +#else + if (auto const home_dir = std::getenv("HOME")) { + return std::filesystem::path(home_dir); + } else { + throw std::runtime_error("$HOME not set"); + } #endif } inline std::vector split(std::string s, std::string delimiter) { - size_t pos_start = 0, pos_end, delim_len = delimiter.length(); - std::string token; - std::vector res; + size_t pos_start = 0, pos_end, delim_len = delimiter.length(); + std::string token; + std::vector res; - while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { - token = s.substr (pos_start, pos_end - pos_start); - pos_start = pos_end + delim_len; - res.push_back (token); - } + while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { + token = s.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + res.push_back(token); + } - res.push_back (s.substr (pos_start)); - return res; + res.push_back(s.substr(pos_start)); + return res; } inline std::string pathsep() { - - #if __COSMOPOLITAN__ - return IsWindows() ? ";" : ":"; - #elif _WIN32 - return ";"; - #else - return ":"; - #endif +#if __COSMOPOLITAN__ + return IsWindows() ? ";" : ":"; +#elif _WIN32 + return ";"; +#else + return ":"; +#endif } -inline std::string join(const std::vector &lst, const std::string &delim) -{ - std::string ret; - for(const auto &s : lst) { - if(!ret.empty()) - ret += delim; - ret += s; - } - return ret; +inline std::string join(const std::vector &lst, + const std::string &delim) { + std::string ret; + for (const auto &s : lst) { + if (!ret.empty()) + ret += delim; + ret += s; + } + return ret; } -} -} +} // namespace utils +} // namespace platformdirs diff --git a/src/platformdirs/version.cpp b/src/platformdirs/version.cpp index 841db40..ae7c68b 100644 --- a/src/platformdirs/version.cpp +++ b/src/platformdirs/version.cpp @@ -1,12 +1,13 @@ #include "version.h" -#include #include #include +#include std::string platformdirs::version::version() { - return std::string(PROJECT_VERSION); + return std::string(PROJECT_VERSION); } std::tuple platformdirs::version::version_tuple() { - return std::make_tuple(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH); + return std::make_tuple(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, + PROJECT_VERSION_PATCH); } diff --git a/src/platformdirs/windows.cpp b/src/platformdirs/windows.cpp new file mode 100644 index 0000000..8a22db2 --- /dev/null +++ b/src/platformdirs/windows.cpp @@ -0,0 +1,189 @@ +#include "windows.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include + +platformdirs::windows::windows::windows( + const std::optional &appname, + const std::variant &appauthor, + const std::optional &version, bool roaming, bool multipath, + bool opinion, bool ensure_exists) + : platformdirs::api::platform_dirs_abc(appname, appauthor, version, roaming, + multipath, opinion, ensure_exists) {} + +auto platformdirs::windows::windows::user_data_dir() const -> std::string { + auto const c = this->roaming ? std::string("CSIDL_APPDATA") + : std::string("CSIDL_LOCAL_APPDATA"); + auto const path = platformdirs::windows::get_win_folder(c); + return this->append_parts(path); +} + +auto platformdirs::windows::windows::append_parts( + const std::string &path, + const platformdirs::windows::windows::append_parts_options &options) const + -> std::string { + auto params = std::vector(); + if (this->appname) { + std::visit( + [¶ms, this](auto &&arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + params.push_back(arg); + } else if constexpr (std::is_same_v) { + params.push_back(this->appname.value()); + } else if constexpr (std::is_same_v) { + if (arg) { + throw std::logic_error("this->appauthor bool must not be true"); + } + // Skip when false. + } + }, + this->appauthor); + params.push_back(this->appname.value()); + if (options.opinion_value && this->opinion) { + params.push_back(options.opinion_value.value()); + } + if (this->version) { + params.push_back(this->version.value()); + } + } + auto path2 = std::filesystem::path(path); + for (auto const p : params) { + path2 = path2 / p; + } + this->optionally_create_directory(path2.string()); + return path2.string(); +} + +auto platformdirs::windows::windows::site_data_dir() const -> std::string { + auto const path = + platformdirs::windows::get_win_folder("CSIDL_COMMON_APPDATA"); + return this->append_parts(path); +} + +auto platformdirs::windows::windows::user_config_dir() const -> std::string { + return this->user_data_dir(); +} + +auto platformdirs::windows::windows::site_config_dir() const -> std::string { + return this->site_data_dir(); +} + +auto platformdirs::windows::windows::user_cache_dir() const -> std::string { + auto const path = + platformdirs::windows::get_win_folder("CSIDL_LOCAL_APPDATA"); + return this->append_parts(path, {.opinion_value = "Cache"}); +} + +auto platformdirs::windows::windows::site_cache_dir() const -> std::string { + auto const path = + platformdirs::windows::get_win_folder("CSIDL_COMMON_APPDATA"); + return this->append_parts(path, {.opinion_value = "Cache"}); +} + +auto platformdirs::windows::windows::user_state_dir() const -> std::string { + return this->user_data_dir(); +} + +auto platformdirs::windows::windows::user_log_dir() const -> std::string { + auto path = this->user_data_dir(); + if (this->opinion) { + path = (std::filesystem::path(path) / "Logs").string(); + this->optionally_create_directory(path); + } + return path; +} + +auto platformdirs::windows::windows::user_documents_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_PERSONAL"); +} + +auto platformdirs::windows::windows::user_downloads_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_DOWNLOADS"); +} + +auto platformdirs::windows::windows::user_pictures_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_MYPICTURES"); +} + +auto platformdirs::windows::windows::user_videos_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_MYVIDEO"); +} + +auto platformdirs::windows::windows::user_music_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_MYMUSIC"); +} + +auto platformdirs::windows::windows::user_desktop_dir() const -> std::string { + return platformdirs::windows::get_win_folder("CSIDL_DESKTOP_DIRECTORY"); +} + +auto platformdirs::windows::windows::user_runtime_dir() const -> std::string { + auto const path = + (std::filesystem::path( + platformdirs::windows::get_win_folder("CSIDL_LOCAL_APPDATA")) / + "Temp") + .string(); + return this->append_parts(path); +} + +auto platformdirs::windows::windows::site_runtime_dir() const -> std::string { + return this->user_runtime_dir(); +} + +auto platformdirs::windows::get_win_folder_from_env_vars( + const std::string &csidl_name) -> std::string { + auto result = platformdirs::windows::get_win_folder_if_csidl_name_not_env_var( + csidl_name); + if (result) { + return result.value(); + } + + std::string env_var_name; + if (csidl_name == "CSIDL_APPDATA") { + env_var_name = "APPDATA"; + } else if (csidl_name == "CSIDL_COMMON_APPDATA") { + env_var_name = "ALLUSERSPROFILE"; + } else if (csidl_name == "CSIDL_LOCAL_APPDATA") { + env_var_name = "LOCALAPPDATA"; + } else { + throw std::runtime_error(fmt::format("Unknown CSIDL name: {}", csidl_name)); + } + + auto result_c_str = std::getenv(env_var_name.c_str()); + if (!result_c_str) { + throw std::runtime_error( + fmt::format("Unset environment variable: {}", env_var_name)); + } + return std::string(result_c_str); +} + +auto platformdirs::windows::get_win_folder_if_csidl_name_not_env_var( + const std::string &csidl_name) -> std::optional { + if (csidl_name == "CSIDL_PERSONAL") { + return (std::filesystem::path(std::getenv("USERPROFILE")) / "Documents") + .string(); + } + if (csidl_name == "CSIDL_DOWNLOADS") { + return (std::filesystem::path(std::getenv("USERPROFILE")) / "Downloads") + .string(); + } + if (csidl_name == "CSIDL_MYPICTURES") { + return (std::filesystem::path(std::getenv("USERPROFILE")) / "Pictures") + .string(); + } + if (csidl_name == "CSIDL_MYVIDEO") { + return (std::filesystem::path(std::getenv("USERPROFILE")) / "Videos") + .string(); + } + if (csidl_name == "CSIDL_MYMUSIC") { + return (std::filesystem::path(std::getenv("USERPROFILE")) / "Music") + .string(); + } + return std::nullopt; +} diff --git a/src/platformdirs/windows.h b/src/platformdirs/windows.h new file mode 100644 index 0000000..1c1cdf8 --- /dev/null +++ b/src/platformdirs/windows.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace platformdirs { +namespace windows { + +auto get_win_folder_from_env_vars(const std::string &csidl_name) -> std::string; + +auto get_win_folder_if_csidl_name_not_env_var(const std::string &csidl_name) + -> std::optional; + +constexpr auto &get_win_folder = get_win_folder_from_env_vars; + +} // namespace windows +} // namespace platformdirs diff --git a/src/platformdirs_exe.cpp b/src/platformdirs_exe.cpp index 7f57cde..9b5c3f8 100644 --- a/src/platformdirs_exe.cpp +++ b/src/platformdirs_exe.cpp @@ -1,84 +1,87 @@ -#include -#include #include +#include +#include int main(int argc, char *argv[]) { - const std::string app_name = "MyApp"; - const std::string app_author = "MyCompany"; + const std::string app_name = "MyApp"; + const std::string app_author = "MyCompany"; - fmt::println("-- platformdirs {}", platformdirs::version_()); + fmt::println("-- platformdirs {} --", platformdirs::version_()); - fmt::println("-- app dirs (with optional 'version')"); - const auto dirs = platformdirs::platform_dirs(app_name, app_author, "1.0"); - fmt::println("user_data_dir: {}", dirs.user_data_dir()); - // fmt::println("user_config_dir: {}", dirs.user_config_dir()); - // fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); - // fmt::println("user_state_dir: {}", dirs.user_state_dir()); - // fmt::println("user_log_dir: {}", dirs.user_log_dir()); - // fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); - // fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); - // fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); - // fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); - // fmt::println("user_music_dir: {}", dirs.user_music_dir()); - // fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); - fmt::println("site_data_dir: {}", dirs.site_data_dir()); - // fmt::println("site_config_dir: {}", dirs.site_config_dir()); - // fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); - // fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); + fmt::println("-- app dirs (with optional 'version')"); + auto dirs = platformdirs::platform_dirs(app_name, app_author, "1.0"); + fmt::println("user_data_dir: {}", dirs.user_data_dir()); + fmt::println("user_config_dir: {}", dirs.user_config_dir()); + fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); + fmt::println("user_state_dir: {}", dirs.user_state_dir()); + fmt::println("user_log_dir: {}", dirs.user_log_dir()); + fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); + fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); + fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); + fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); + fmt::println("user_music_dir: {}", dirs.user_music_dir()); + fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); + fmt::println("site_data_dir: {}", dirs.site_data_dir()); + fmt::println("site_config_dir: {}", dirs.site_config_dir()); + fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); + fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); - // fmt::println("-- app dirs (without optional 'version')"); - // const auto dirs = platformdirs::platform_dirs(app_name, app_author); - // fmt::println("user_data_dir: {}", dirs.user_data_dir()); - // fmt::println("user_config_dir: {}", dirs.user_config_dir()); - // fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); - // fmt::println("user_state_dir: {}", dirs.user_state_dir()); - // fmt::println("user_log_dir: {}", dirs.user_log_dir()); - // fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); - // fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); - // fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); - // fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); - // fmt::println("user_music_dir: {}", dirs.user_music_dir()); - // fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); - // fmt::println("site_data_dir: {}", dirs.site_data_dir()); - // fmt::println("site_config_dir: {}", dirs.site_config_dir()); - // fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); - // fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); + fmt::println(""); + fmt::println("-- app dirs (without optional 'version')"); + dirs = platformdirs::platform_dirs(app_name, app_author); + fmt::println("user_data_dir: {}", dirs.user_data_dir()); + fmt::println("user_config_dir: {}", dirs.user_config_dir()); + fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); + fmt::println("user_state_dir: {}", dirs.user_state_dir()); + fmt::println("user_log_dir: {}", dirs.user_log_dir()); + fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); + fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); + fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); + fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); + fmt::println("user_music_dir: {}", dirs.user_music_dir()); + fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); + fmt::println("site_data_dir: {}", dirs.site_data_dir()); + fmt::println("site_config_dir: {}", dirs.site_config_dir()); + fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); + fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); - // fmt::println("-- app dirs (without optional 'appauthor')"); - // const auto dirs = platformdirs::platform_dirs(app_name); - // fmt::println("user_data_dir: {}", dirs.user_data_dir()); - // fmt::println("user_config_dir: {}", dirs.user_config_dir()); - // fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); - // fmt::println("user_state_dir: {}", dirs.user_state_dir()); - // fmt::println("user_log_dir: {}", dirs.user_log_dir()); - // fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); - // fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); - // fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); - // fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); - // fmt::println("user_music_dir: {}", dirs.user_music_dir()); - // fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); - // fmt::println("site_data_dir: {}", dirs.site_data_dir()); - // fmt::println("site_config_dir: {}", dirs.site_config_dir()); - // fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); - // fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); + fmt::println(""); + fmt::println("-- app dirs (without optional 'appauthor')"); + dirs = platformdirs::platform_dirs(app_name); + fmt::println("user_data_dir: {}", dirs.user_data_dir()); + fmt::println("user_config_dir: {}", dirs.user_config_dir()); + fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); + fmt::println("user_state_dir: {}", dirs.user_state_dir()); + fmt::println("user_log_dir: {}", dirs.user_log_dir()); + fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); + fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); + fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); + fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); + fmt::println("user_music_dir: {}", dirs.user_music_dir()); + fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); + fmt::println("site_data_dir: {}", dirs.site_data_dir()); + fmt::println("site_config_dir: {}", dirs.site_config_dir()); + fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); + fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); - // fmt::println("-- app dirs (with disabled 'appauthor')"); - // const auto dirs = platformdirs::platform_dirs(app_name, false); - // fmt::println("user_data_dir: {}", dirs.user_data_dir()); - // fmt::println("user_config_dir: {}", dirs.user_config_dir()); - // fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); - // fmt::println("user_state_dir: {}", dirs.user_state_dir()); - // fmt::println("user_log_dir: {}", dirs.user_log_dir()); - // fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); - // fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); - // fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); - // fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); - // fmt::println("user_music_dir: {}", dirs.user_music_dir()); - // fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); - // fmt::println("site_data_dir: {}", dirs.site_data_dir()); - // fmt::println("site_config_dir: {}", dirs.site_config_dir()); - // fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); - // fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); + fmt::println(""); + fmt::println("-- app dirs (with disabled 'appauthor')"); + dirs = platformdirs::platform_dirs(app_name, false); + fmt::println("user_data_dir: {}", dirs.user_data_dir()); + fmt::println("user_config_dir: {}", dirs.user_config_dir()); + fmt::println("user_cache_dir: {}", dirs.user_cache_dir()); + fmt::println("user_state_dir: {}", dirs.user_state_dir()); + fmt::println("user_log_dir: {}", dirs.user_log_dir()); + fmt::println("user_documents_dir: {}", dirs.user_documents_dir()); + fmt::println("user_downloads_dir: {}", dirs.user_downloads_dir()); + fmt::println("user_pictures_dir: {}", dirs.user_pictures_dir()); + fmt::println("user_videos_dir: {}", dirs.user_videos_dir()); + fmt::println("user_music_dir: {}", dirs.user_music_dir()); + fmt::println("user_runtime_dir: {}", dirs.user_runtime_dir()); + fmt::println("site_data_dir: {}", dirs.site_data_dir()); + fmt::println("site_config_dir: {}", dirs.site_config_dir()); + fmt::println("site_cache_dir: {}", dirs.site_cache_dir()); + fmt::println("site_runtime_dir: {}", dirs.site_runtime_dir()); - return 0; + return 0; }