// Copyright 2021 Jean Pierre Cimalando // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 // #pragma once #include "ysfx.h" #include #include #include #include #include #include #if defined(__APPLE__) # include #endif #if !defined(_WIN32) && !defined(__FreeBSD__) # include #else # include #endif #if defined(YSFX_NO_STANDARD_MUTEX) # include "WDL/mutex.h" #endif namespace ysfx { YSFX_DEFINE_AUTO_PTR(FILE_u, FILE, fclose); FILE *fopen_utf8(const char *path, const char *mode); int64_t fseek_lfs(FILE *stream, int64_t off, int whence); int64_t ftell_lfs(FILE *stream); //------------------------------------------------------------------------------ #if !defined(_WIN32) using c_locale_t = locale_t; #else using c_locale_t = _locale_t; #endif c_locale_t c_numeric_locale(); //------------------------------------------------------------------------------ #if !defined(_WIN32) # define ysfx_alloca(n) alloca((n)) #else # define ysfx_alloca(n) _malloca((n)) #endif //------------------------------------------------------------------------------ #if !defined(YSFX_NO_STANDARD_MUTEX) using mutex = std::mutex; #else class mutex { public: void lock() { m_mutex.Enter(); } void unlock() { m_mutex.Leave(); } private: WDL_Mutex m_mutex; }; #endif //------------------------------------------------------------------------------ using string_list = std::vector; double c_atof(const char *text, c_locale_t loc); double c_strtod(const char *text, char **endp, c_locale_t loc); double dot_atof(const char *text); double dot_strtod(const char *text, char **endp); bool ascii_isspace(char c); bool ascii_isalpha(char c); char ascii_tolower(char c); char ascii_toupper(char c); int ascii_casecmp(const char *a, const char *b); uint32_t latin1_toupper(uint32_t c); uint32_t latin1_tolower(uint32_t c); char *strdup_using_new(const char *src); string_list split_strings_noempty(const char *input, bool(*pred)(char)); std::string trim(const char *input, bool(*pred)(char)); //------------------------------------------------------------------------------ void pack_u32le(uint32_t value, uint8_t data[4]); void pack_f32le(float value, uint8_t data[4]); uint32_t unpack_u32le(const uint8_t data[4]); float unpack_f32le(const uint8_t data[4]); //------------------------------------------------------------------------------ std::vector decode_base64(const char *text, size_t len = ~(size_t)0); std::string encode_base64(const uint8_t *data, size_t len); //------------------------------------------------------------------------------ using file_uid = std::pair; bool get_file_uid(const char *path, file_uid &uid); bool get_stream_file_uid(FILE *stream, file_uid &uid); bool get_descriptor_file_uid(int fd, file_uid &uid); #if defined(_WIN32) bool get_handle_file_uid(void *handle, file_uid &uid); #endif //------------------------------------------------------------------------------ struct split_path_t { std::string drive; std::string dir; std::string file; }; // check if the character is a path separator bool is_path_separator(char ch); // break down a path into individual components split_path_t split_path(const char *path); // get the file name part (all after the final '/' separator) std::string path_file_name(const char *path); // get the directory part (all up to the '/' separator, inclusive) std::string path_directory(const char *path); // add the final '/' separator if absent; if empty, does nothing std::string path_ensure_final_separator(const char *path); // compare the tail of the path with the suffix, case-insensitively bool path_has_suffix(const char *path, const char *suffix); // check whether the path is relative bool path_is_relative(const char *path); //------------------------------------------------------------------------------ // check whether a file exists on disk bool exists(const char *path); // list the elements of a directory; directories are distinguished with a final '/' string_list list_directory(const char *path); // visit the root and subdirectories in depth-first order void visit_directories(const char *rootpath, bool (*visit)(const std::string &, void *), void *data); // resolve a path which matches root/fragment, where fragment is case-insensitive (0=failed, 1=exact, 2=inexact) int case_resolve(const char *root, const char *fragment, std::string &result); //------------------------------------------------------------------------------ #if defined(_WIN32) std::wstring widen(const std::string &u8str); std::wstring widen(const char *u8data, size_t u8len = ~(size_t)0); std::string narrow(const std::wstring &wstr); std::string narrow(const wchar_t *wdata, size_t wlen = ~(size_t)0); #endif //------------------------------------------------------------------------------ template class scope_guard { public: explicit scope_guard(F &&f) : f(std::forward(f)), a(true) {} scope_guard(scope_guard &&o) : f(std::move(o.f)), a(o.a) { o.a = false; } ~scope_guard() { if (a) f(); } void disarm() { a = false; } private: F f; bool a; scope_guard(const scope_guard &) = delete; scope_guard &operator=(const scope_guard &) = delete; }; template scope_guard defer(F &&f) { return scope_guard(std::forward(f)); } } // namespace ysfx