Fcitx
standardpaths.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2025-2025 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_STANDARDPATHS_H_
8 #define _FCITX_UTILS_STANDARDPATHS_H_
9 
10 #include <sys/types.h>
11 #include <cstdint>
12 #include <filesystem>
13 #include <functional>
14 #include <map>
15 #include <memory>
16 #include <optional>
17 #include <string>
18 #include <unordered_map>
19 #include <vector>
20 #include <fcitx-utils/fcitxutils_export.h>
21 #include <fcitx-utils/flags.h>
22 #include <fcitx-utils/macros.h>
23 #include <fcitx-utils/unixfd.h>
24 #include <span>
25 
26 /**
27  * \addtogroup FcitxUtils
28  * \{
29  * \file
30  * \brief New Utility classes to handle application specific path.
31  *
32  * Comparing to the existing ones, it removes some obsolette functions, and
33  * remove The ones can more easily implemented with std::filesystems.
34  */
35 
36 namespace fcitx {
37 
38 class StandardPathsPrivate;
39 
40 /** \brief Enum for location type. */
41 enum class StandardPathsType {
42  Config,
43  PkgConfig,
44  Data,
45  Cache,
46  Runtime,
47  Addon,
48  PkgData
49 };
50 enum class StandardPathsMode : uint8_t {
51  User = (1 << 0),
52  System = (1 << 1),
53  Default = User | System,
54 };
55 
56 /**
57  * Options for standard paths.
58  *
59  * This flag controls the behavior of StandardPaths.
60  * If you want to skip some paths, you can use these flags.
61  * User Path and System Path are derived from platform specific variables.
62  * Built-in Path is based on installation path.
63  */
64 enum class StandardPathsOption : uint8_t {
65  SkipUserPath = (1 << 0), // Skip user path
66  SkipSystemPath = (1 << 1), // Skip system path
67  SkipBuiltInPath = (1 << 2), // Skip built-in path
68 };
69 
72 using StandardPathsFilterCallback =
73  std::function<bool(const std::filesystem::path &)>;
74 
75 namespace pathfilter {
76 
77 static inline auto extension(const std::string &ext) {
78  return [ext](const std::filesystem::path &path) {
79  return path.extension() == ext;
80  };
81 }
82 
83 } // namespace pathfilter
84 
85 class FCITXUTILS_EXPORT StandardPaths {
86 public:
87  /**
88  * Allow to construct a StandardPath with customized internal value.
89  *
90  * @param packageName the sub directory under other paths.
91  * @param builtInPath this will override the value from fcitxPath.
92  * @param options options to customize the behavior.
93  */
94  explicit StandardPaths(
95  const std::string &packageName,
96  const std::unordered_map<
97  std::string, std::vector<std::filesystem::path>> &builtInPath,
98  StandardPathsOptions options);
99 
100  virtual ~StandardPaths();
101 
102  /**
103  * \brief Return the global instance of StandardPath.
104  */
105  static const StandardPaths &global();
106 
107  /** \brief Return fcitx specific path defined at compile time.
108  *
109  * Currently, available value of fcitxPath are:
110  * datadir, pkgdatadir, libdir, bindir, localedir, addondir, libdatadir.
111  * Otherwise it will return nullptr.
112  */
113  static std::filesystem::path
114  fcitxPath(const char *path, const std::filesystem::path &subPath = {});
115 
116  static std::filesystem::path
117  findExecutable(const std::filesystem::path &name);
118 
119  static bool hasExecutable(const std::filesystem::path &name);
120 
121  /**
122  * \brief Get user writable directory for given type.
123  *
124  * The path will be empty if there is no relevant user directory.
125  */
126  const std::filesystem::path &userDirectory(StandardPathsType type) const;
127 
128  /**
129  * \brief Get all directories in the order of priority.
130  */
131  std::span<const std::filesystem::path>
132  directories(StandardPathsType type,
133  StandardPathsModes modes = StandardPathsMode::Default) const;
134 
135  /** \brief Check if a file exists. */
136  std::filesystem::path
137  locate(StandardPathsType type, const std::filesystem::path &path,
138  StandardPathsModes modes = StandardPathsMode::Default) const;
139 
140  /**
141  * \brief Check if path exists in all directories.
142  *
143  * It will enumerate all directories returned by directories() and check
144  * if the file exists. The order is same as directories().
145  */
146  std::vector<std::filesystem::path>
147  locateAll(StandardPathsType type, const std::filesystem::path &path,
148  StandardPathsModes modes = StandardPathsMode::Default) const;
149 
150  /** \brief All subpath under path with filter. */
151  std::map<std::filesystem::path, std::filesystem::path>
152  locate(StandardPathsType type, const std::filesystem::path &path,
153  const StandardPathsFilterCallback &callback,
154  StandardPathsModes modes = StandardPathsMode::Default) const;
155 
156  /** \brief Open the first matched and succeeded file for read.
157  *
158  * This function is preferred over locate if you just want to open the
159  * file. Then you can avoid the race condition.
160  */
161  UnixFD open(StandardPathsType type, const std::filesystem::path &path,
162  StandardPathsModes modes = StandardPathsMode::Default,
163  std::filesystem::path *outPath = nullptr) const;
164 
165  /**
166  * \brief Open the path.
167  *
168  * This function will use _wopen on Windows and open on Unix.
169  * By default, it will open the file with O_RDONLY.
170  * _O_BINARY will be set on Windows.
171  */
172  static UnixFD openPath(const std::filesystem::path &path,
173  std::optional<int> flags = std::nullopt,
174  std::optional<mode_t> mode = std::nullopt);
175 
176  /** \brief Open the all matched and file for read.
177  */
178  std::vector<UnixFD>
179  openAll(StandardPathsType type, const std::filesystem::path &path,
180  StandardPathsModes modes = StandardPathsMode::Default,
181  std::vector<std::filesystem::path> *outPath = nullptr) const;
182 
183  /**
184  * \brief Save the file safely with write and rename to make sure the
185  * operation is atomic.
186  *
187  * Callback shall not close the file descriptor. If the API you are using
188  * does cannot do that, you may use UnixFD to help you dup it first.
189  *
190  * \param callback Callback function that accept a file descriptor and
191  * return whether the save if success or not.
192  */
193  bool safeSave(StandardPathsType type, const std::filesystem::path &pathOrig,
194  const std::function<bool(int)> &callback) const;
195 
196  int64_t
197  timestamp(StandardPathsType type, const std::filesystem::path &path,
198  StandardPathsModes modes = StandardPathsMode::Default) const;
199 
200  /**
201  * Sync system umask to internal state. This will affect the file
202  * permission created by safeSave.
203  *
204  * @see safeSave
205  */
206  void syncUmask() const;
207 
208  /**
209  * Whether this StandardPath is configured to Skip built-in path.
210  *
211  * Built-in path is usually configured at build time, hardcoded.
212  * In portable environment (Install prefix is not fixed), this should be
213  * set to false.
214  */
215  bool skipBuiltInPath() const;
216 
217  /**
218  * Whether this StandardPath is configured to Skip user path.
219  *
220  */
221  bool skipUserPath() const;
222 
223  /**
224  * Whether this StandardPath is configured to Skip system path.
225  */
226  bool skipSystemPath() const;
227 
228  /**
229  * \brief Get the options for the StandardPaths.
230  *
231  * This function returns the current configuration options for the
232  * StandardPaths instance.
233  */
234 
235  StandardPathsOptions options() const;
236 
237 private:
238  std::unique_ptr<StandardPathsPrivate> d_ptr;
239  FCITX_DECLARE_PRIVATE(StandardPaths);
240 };
241 
242 template <typename T>
244 
245 } // namespace fcitx
246 
247 #endif // _FCITX_UTILS_STANDARDPATHS_H_
Class wrap around the unix fd.
Definition: unixfd.h:22
StandardPathsOption
Options for standard paths.
Definition: standardpaths.h:64
StandardPathsType
Enum for location type.
Definition: standardpaths.h:41
Definition: action.cpp:17
Utility class to handle unix file decriptor.
Class provides bit flag support for Enum.
Definition: flags.h:33
Helper template class to make easier to use type safe enum flags.