/* ** Copyright (C) 2023 Dirk-Jan C. Binnema ** ** This program is free software; you can redistribute it and/or modify it ** under the terms of the GNU General Public License as published by the ** Free Software Foundation; either version 3, or (at your option) any ** later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software Foundation, ** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ #ifndef MU_UTILS_FILE_HH__ #define MU_UTILS_FILE_HH__ #include #include #include #include #include #include #include namespace Mu { /** * Check if the directory has the given attributes * * @param path path to dir * @param readable is it readable? * @param writeable is it writable? * * @return true if is is a directory with given attributes; false otherwise. */ bool check_dir(const std::string& path, bool readable, bool writeable); /** * See g_canonicalize_filename * * @param filename * @param relative_to * * @return */ std::string canonicalize_filename(const std::string& path, const std::string& relative_to=""); /** * Expand the filesystem path (as per wordexp(3)) * * @param str a filesystem path string * * @return the expanded string or some error */ Result expand_path(const std::string& str); /** * Get the basename for path, i.e. without leading directory component, * @see g_path_get_basename * * @param path * * @return the basename */ std::string basename(const std::string& path); /** * Get the dirname for path, i.e. without leading directory component, * @see g_path_get_dirname * * @param path * * @return the dirname */ std::string dirname(const std::string& path); /* * for OSs without support for direntry->d_type, like Solaris */ #ifndef DT_UNKNOWN enum { DT_UNKNOWN = 0, #define DT_UNKNOWN DT_UNKNOWN DT_FIFO = 1, #define DT_FIFO DT_FIFO DT_CHR = 2, #define DT_CHR DT_CHR DT_DIR = 4, #define DT_DIR DT_DIR DT_BLK = 6, #define DT_BLK DT_BLK DT_REG = 8, #define DT_REG DT_REG DT_LNK = 10, #define DT_LNK DT_LNK DT_SOCK = 12, #define DT_SOCK DT_SOCK DT_WHT = 14 #define DT_WHT DT_WHT }; #endif /*DT_UNKNOWN*/ /** * get the d_type (as in direntry->d_type) for the file at path, using either * stat(3) or lstat(3) * * @param path full path * @param use_lstat whether to use lstat (otherwise use stat) * * @return DT_REG, DT_DIR, DT_LNK, or DT_UNKNOWN (other values are not supported * currently) */ uint8_t determine_dtype(const std::string& path, bool use_lstat=false); /** * Well-known runtime paths * */ enum struct RuntimePath { XapianDb, Cache, LogFile, Config, Scripts, Bookmarks }; /** * Get some well-known Path for internal use when don't have * access to the command-line * * @param path the RuntimePath to find * @param muhome path to muhome directory, or empty for the default. * * @return the path name */ std::string runtime_path(RuntimePath path, const std::string& muhome=""); /** * Join path components into a path (with '/') * * @param s a string-convertible value * @param args 0 or more string-convertible values * * @return the path */ static inline std::string join_paths() { return {}; } template std::string join_paths_(S&& s) { return std::string{s}; } template std::string join_paths_(S&& s, Args...args) { static std::string sepa{"/"}; auto&& str{std::string{std::forward(s)}}; if (auto&& rest{join_paths_(std::forward(args)...)}; !rest.empty()) str += (sepa + rest); return str; } template std::string join_paths(S&& s, Args...args) { constexpr auto sepa = '/'; auto path = join_paths_(std::forward(s), std::forward(args)...); auto c{0U}; while (c < path.size()) { if (path[c] != sepa) { ++c; continue; } while (path[++c] == '/') { path.erase(c, 1); --c; } } return path; } /** * Like g_cancellable_new(), but automatically cancels itself * after timeout * * @param timeout timeout in millisecs * * @return A GCancellable* instances; free with g_object_unref() when * no longer needed. */ GCancellable* g_cancellable_new_with_timeout(guint timeout); /** * Read for standard input * * @return data from standard input or an error. */ Result read_from_stdin(); /** * Create a randomly-named temporary directory * * @return name of the temporary directory or an error. */ Result make_temp_dir(); /** * Remove a directory, recursively. Does not have to be empty. * * @param path path to directory * * @return Ok() or an error. */ Result remove_directory(const std::string& path); /** * Run some system command. * * @param args a list of commmand line arguments (like argv) * @param try_setsid whether to try setsid(2) (see its manpage for details) if this * system supports it. * * @return Ok(exit code) or an error. Note that exit-code != 0 is _not_ considered an error from the * perspective of run_command, but is for run_command0 */ struct CommandOutput { int exit_code; std::string standard_out; std::string standard_err; }; Result run_command(std::initializer_list args, bool try_setsid=false); Result run_command0(std::initializer_list args, bool try_setsid=false); /** * Try to 'play' (ie., open with it's associated program) a file. On MacOS, the * the program 'open' is used for this; on other platforms 'xdg-open' to do the * actual opening. In addition you can set it to another program by setting thep * MU_PLAY_PROGRAM environment variable * * This requires a 'native' file, see g_file_is_native() * * @param path full path of the file to open * * @return Ok() if succeeded, some error otherwise. */ Result play(const std::string& path); /** * Find program in PATH * * @param name the name of the program * * @return either the full path to program, or Nothing if not found. */ Option program_in_path(const std::string& name); } // namespace Mu #endif /* MU_UTILS_FILE_HH__ */