1 //===-- FileSpec.h ----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_UTILITY_FILESPEC_H 10 #define LLDB_UTILITY_FILESPEC_H 11 12 #include <functional> 13 #include <optional> 14 #include <string> 15 16 #include "lldb/Utility/ConstString.h" 17 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/Support/FileSystem.h" 20 #include "llvm/Support/FormatVariadic.h" 21 #include "llvm/Support/Path.h" 22 23 #include <cstddef> 24 #include <cstdint> 25 26 namespace lldb_private { 27 class Stream; 28 } 29 namespace llvm { 30 class Triple; 31 } 32 namespace llvm { 33 class raw_ostream; 34 } 35 namespace llvm { 36 template <typename T> class SmallVectorImpl; 37 } 38 39 namespace lldb_private { 40 41 /// \class FileSpec FileSpec.h "lldb/Utility/FileSpec.h" 42 /// A file utility class. 43 /// 44 /// A file specification class that divides paths up into a directory 45 /// and basename. These string values of the paths are put into uniqued string 46 /// pools for fast comparisons and efficient memory usage. 47 /// 48 /// Another reason the paths are split into the directory and basename is to 49 /// allow efficient debugger searching. Often in a debugger the user types in 50 /// the basename of the file, for example setting a breakpoint by file and 51 /// line, or specifying a module (shared library) to limit the scope in which 52 /// to execute a command. The user rarely types in a full path. When the paths 53 /// are already split up, it makes it easy for us to compare only the 54 /// basenames of a lot of file specifications without having to split up the 55 /// file path each time to get to the basename. 56 class FileSpec { 57 public: 58 using Style = llvm::sys::path::Style; 59 60 FileSpec(); 61 62 /// Constructor with path. 63 /// 64 /// Takes a path to a file which can be just a filename, or a full path. If 65 /// \a path is not nullptr or empty, this function will call 66 /// FileSpec::SetFile (const char *path). 67 /// 68 /// \param[in] path 69 /// The full or partial path to a file. 70 /// 71 /// \param[in] style 72 /// The style of the path 73 /// 74 /// \see FileSpec::SetFile (const char *path) 75 explicit FileSpec(llvm::StringRef path, Style style = Style::native); 76 77 explicit FileSpec(llvm::StringRef path, const llvm::Triple &triple); 78 79 bool DirectoryEquals(const FileSpec &other) const; 80 81 bool FileEquals(const FileSpec &other) const; 82 83 /// Equal to operator 84 /// 85 /// Tests if this object is equal to \a rhs. 86 /// 87 /// \param[in] rhs 88 /// A const FileSpec object reference to compare this object 89 /// to. 90 /// 91 /// \return 92 /// \b true if this object is equal to \a rhs, \b false 93 /// otherwise. 94 bool operator==(const FileSpec &rhs) const; 95 96 /// Not equal to operator 97 /// 98 /// Tests if this object is not equal to \a rhs. 99 /// 100 /// \param[in] rhs 101 /// A const FileSpec object reference to compare this object 102 /// to. 103 /// 104 /// \return 105 /// \b true if this object is equal to \a rhs, \b false 106 /// otherwise. 107 bool operator!=(const FileSpec &rhs) const; 108 109 /// Less than to operator 110 /// 111 /// Tests if this object is less than \a rhs. 112 /// 113 /// \param[in] rhs 114 /// A const FileSpec object reference to compare this object 115 /// to. 116 /// 117 /// \return 118 /// \b true if this object is less than \a rhs, \b false 119 /// otherwise. 120 bool operator<(const FileSpec &rhs) const; 121 122 /// Convert to pointer operator. 123 /// 124 /// This allows code to check a FileSpec object to see if it contains 125 /// anything valid using code such as: 126 /// 127 /// \code 128 /// FileSpec file_spec(...); 129 /// if (file_spec) 130 /// { ... 131 /// \endcode 132 /// 133 /// \return 134 /// A pointer to this object if either the directory or filename 135 /// is valid, nullptr otherwise. 136 explicit operator bool() const; 137 138 /// Logical NOT operator. 139 /// 140 /// This allows code to check a FileSpec object to see if it is invalid 141 /// using code such as: 142 /// 143 /// \code 144 /// FileSpec file_spec(...); 145 /// if (!file_spec) 146 /// { ... 147 /// \endcode 148 /// 149 /// \return 150 /// Returns \b true if the object has an empty directory and 151 /// filename, \b false otherwise. 152 bool operator!() const; 153 154 /// Clears the object state. 155 /// 156 /// Clear this object by releasing both the directory and filename string 157 /// values and reverting them to empty strings. 158 void Clear(); 159 160 /// Compare two FileSpec objects. 161 /// 162 /// If \a full is true, then both the directory and the filename must match. 163 /// If \a full is false, then the directory names for \a lhs and \a rhs are 164 /// only compared if they are both not empty. This allows a FileSpec object 165 /// to only contain a filename and it can match FileSpec objects that have 166 /// matching filenames with different paths. 167 /// 168 /// \param[in] lhs 169 /// A const reference to the Left Hand Side object to compare. 170 /// 171 /// \param[in] rhs 172 /// A const reference to the Right Hand Side object to compare. 173 /// 174 /// \param[in] full 175 /// If true, then both the directory and filenames will have to 176 /// match for a compare to return zero (equal to). If false 177 /// and either directory from \a lhs or \a rhs is empty, then 178 /// only the filename will be compared, else a full comparison 179 /// is done. 180 /// 181 /// \return -1 if \a lhs is less than \a rhs, 0 if \a lhs is equal to \a rhs, 182 /// 1 if \a lhs is greater than \a rhs 183 static int Compare(const FileSpec &lhs, const FileSpec &rhs, bool full); 184 185 static bool Equal(const FileSpec &a, const FileSpec &b, bool full); 186 187 /// Match FileSpec \a pattern against FileSpec \a file. If \a pattern has a 188 /// directory component, then the \a file must have the same directory 189 /// component. Otherwise, just it matches just the filename. An empty \a 190 /// pattern matches everything. 191 static bool Match(const FileSpec &pattern, const FileSpec &file); 192 193 /// Attempt to guess path style for a given path string. It returns a style, 194 /// if it was able to make a reasonable guess, or std::nullopt if it wasn't. 195 /// The guess will be correct if the input path was a valid absolute path on 196 /// the system which produced it. On other paths the result of this function 197 /// is unreliable (e.g. "c:\foo.txt" is a valid relative posix path). 198 static std::optional<Style> GuessPathStyle(llvm::StringRef absolute_path); 199 200 /// Case sensitivity of path. 201 /// 202 /// \return 203 /// \b true if the file path is case sensitive (POSIX), false 204 /// if case insensitive (Windows). 205 bool IsCaseSensitive() const { return is_style_posix(m_style); } 206 207 /// Dump this object to a Stream. 208 /// 209 /// Dump the object to the supplied stream \a s. If the object contains a 210 /// valid directory name, it will be displayed followed by a directory 211 /// delimiter, and the filename. 212 /// 213 /// \param[in] s 214 /// The stream to which to dump the object description. 215 void Dump(llvm::raw_ostream &s) const; 216 217 Style GetPathStyle() const; 218 219 /// Directory string const get accessor. 220 /// 221 /// \return 222 /// A const reference to the directory string object. 223 const ConstString &GetDirectory() const { return m_directory; } 224 225 /// Directory string set accessor. 226 /// 227 /// \param[in] directory 228 /// The value to replace the directory with. 229 void SetDirectory(ConstString directory); 230 void SetDirectory(llvm::StringRef directory); 231 232 /// Clear the directory in this object. 233 void ClearDirectory(); 234 235 236 /// Filename string const get accessor. 237 /// 238 /// \return 239 /// A const reference to the filename string object. 240 const ConstString &GetFilename() const { return m_filename; } 241 242 /// Filename string set accessor. 243 /// 244 /// \param[in] filename 245 /// The const string to replace the directory with. 246 void SetFilename(ConstString filename); 247 void SetFilename(llvm::StringRef filename); 248 249 /// Clear the filename in this object. 250 void ClearFilename(); 251 252 /// Returns true if the filespec represents an implementation source file 253 /// (files with a ".c", ".cpp", ".m", ".mm" (many more) extension). 254 /// 255 /// \return 256 /// \b true if the FileSpec represents an implementation source 257 /// file, \b false otherwise. 258 bool IsSourceImplementationFile() const; 259 260 /// Returns true if the filespec represents a relative path. 261 /// 262 /// \return 263 /// \b true if the filespec represents a relative path, 264 /// \b false otherwise. 265 bool IsRelative() const; 266 267 /// Returns true if the filespec represents an absolute path. 268 /// 269 /// \return 270 /// \b true if the filespec represents an absolute path, 271 /// \b false otherwise. 272 bool IsAbsolute() const; 273 274 /// Make the FileSpec absolute by treating it relative to \a dir. Absolute 275 /// FileSpecs are never changed by this function. 276 void MakeAbsolute(const FileSpec &dir); 277 278 /// Temporary helper for FileSystem change. 279 void SetPath(llvm::StringRef p) { SetFile(p); } 280 281 /// Extract the full path to the file. 282 /// 283 /// Extract the directory and path into a fixed buffer. This is needed as 284 /// the directory and path are stored in separate string values. 285 /// 286 /// \param[out] path 287 /// The buffer in which to place the extracted full path. 288 /// 289 /// \param[in] max_path_length 290 /// The maximum length of \a path. 291 /// 292 /// \return 293 /// Returns the number of characters that would be needed to 294 /// properly copy the full path into \a path. If the returned 295 /// number is less than \a max_path_length, then the path is 296 /// properly copied and terminated. If the return value is 297 /// >= \a max_path_length, then the path was truncated (but is 298 /// still NULL terminated). 299 size_t GetPath(char *path, size_t max_path_length, 300 bool denormalize = true) const; 301 302 /// Extract the full path to the file. 303 /// 304 /// Extract the directory and path into a std::string, which is returned. 305 /// 306 /// \return 307 /// Returns a std::string with the directory and filename 308 /// concatenated. 309 std::string GetPath(bool denormalize = true) const; 310 311 /// Get the full path as a ConstString. 312 /// 313 /// This method should only be used when you need a ConstString or the 314 /// const char * from a ConstString to ensure permanent lifetime of C string. 315 /// Anyone needing the path temporarily should use the GetPath() method that 316 /// returns a std:string. 317 ConstString GetPathAsConstString(bool denormalize = true) const; 318 319 /// Extract the full path to the file. 320 /// 321 /// Extract the directory and path into an llvm::SmallVectorImpl<> 322 void GetPath(llvm::SmallVectorImpl<char> &path, 323 bool denormalize = true) const; 324 325 /// Extract the extension of the file. 326 /// 327 /// Returns a ConstString that represents the extension of the filename for 328 /// this FileSpec object. If this object does not represent a file, or the 329 /// filename has no extension, ConstString(nullptr) is returned. The dot 330 /// ('.') character is the first character in the returned string. 331 /// 332 /// \return Returns the extension of the file as a StringRef. 333 llvm::StringRef GetFileNameExtension() const; 334 335 /// Return the filename without the extension part 336 /// 337 /// Returns a ConstString that represents the filename of this object 338 /// without the extension part (e.g. for a file named "foo.bar", "foo" is 339 /// returned) 340 /// 341 /// \return Returns the filename without extension as a ConstString object. 342 ConstString GetFileNameStrippingExtension() const; 343 344 /// Get the memory cost of this object. 345 /// 346 /// Return the size in bytes that this object takes in memory. This returns 347 /// the size in bytes of this object, not any shared string values it may 348 /// refer to. 349 /// 350 /// \return 351 /// The number of bytes that this object occupies in memory. 352 size_t MemorySize() const; 353 354 /// Change the file specified with a new path. 355 /// 356 /// Update the contents of this object with a new path. The path will be 357 /// split up into a directory and filename and stored as uniqued string 358 /// values for quick comparison and efficient memory usage. 359 /// 360 /// \param[in] path 361 /// A full, partial, or relative path to a file. 362 /// 363 /// \param[in] style 364 /// The style for the given path. 365 void SetFile(llvm::StringRef path, Style style); 366 367 /// Change the file specified with a new path. 368 /// 369 /// Update the contents of this object with a new path. The path will be 370 /// split up into a directory and filename and stored as uniqued string 371 /// values for quick comparison and efficient memory usage. 372 /// 373 /// \param[in] path 374 /// A full, partial, or relative path to a file. 375 /// 376 /// \param[in] triple 377 /// The triple which is used to set the Path style. 378 void SetFile(llvm::StringRef path, const llvm::Triple &triple); 379 380 bool IsResolved() const { return m_is_resolved; } 381 382 /// Set if the file path has been resolved or not. 383 /// 384 /// If you know a file path is already resolved and avoided passing a \b 385 /// true parameter for any functions that take a "bool resolve_path" 386 /// parameter, you can set the value manually using this call to make sure 387 /// we don't try and resolve it later, or try and resolve a path that has 388 /// already been resolved. 389 /// 390 /// \param[in] is_resolved 391 /// A boolean value that will replace the current value that 392 /// indicates if the paths in this object have been resolved. 393 void SetIsResolved(bool is_resolved) { m_is_resolved = is_resolved; } 394 395 FileSpec CopyByAppendingPathComponent(llvm::StringRef component) const; 396 FileSpec CopyByRemovingLastPathComponent() const; 397 398 void PrependPathComponent(llvm::StringRef component); 399 void PrependPathComponent(const FileSpec &new_path); 400 401 void AppendPathComponent(llvm::StringRef component); 402 void AppendPathComponent(const FileSpec &new_path); 403 404 /// Removes the last path component by replacing the current path with its 405 /// parent. When the current path has no parent, this is a no-op. 406 /// 407 /// \return 408 /// A boolean value indicating whether the path was updated. 409 bool RemoveLastPathComponent(); 410 411 /// Gets the components of the FileSpec's path. 412 /// For example, given the path: 413 /// /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation 414 /// 415 /// This function returns: 416 /// {"System", "Library", "PrivateFrameworks", "UIFoundation.framework", 417 /// "UIFoundation"} 418 /// \return 419 /// A std::vector of llvm::StringRefs for each path component. 420 /// The lifetime of the StringRefs is tied to the lifetime of the FileSpec. 421 std::vector<llvm::StringRef> GetComponents() const; 422 423 protected: 424 // Convenience method for setting the file without changing the style. 425 void SetFile(llvm::StringRef path); 426 427 /// Called anytime m_directory or m_filename is changed to clear any cached 428 /// state in this object. 429 void PathWasModified() { 430 m_is_resolved = false; 431 m_absolute = Absolute::Calculate; 432 } 433 434 enum class Absolute : uint8_t { 435 Calculate, 436 Yes, 437 No 438 }; 439 440 // Member variables 441 ConstString m_directory; ///< The uniqued directory path 442 ConstString m_filename; ///< The uniqued filename path 443 mutable bool m_is_resolved = false; ///< True if this path has been resolved. 444 mutable Absolute m_absolute = Absolute::Calculate; ///< Cache absoluteness. 445 Style m_style; ///< The syntax that this path uses (e.g. Windows / Posix) 446 }; 447 448 /// Dump a FileSpec object to a stream 449 Stream &operator<<(Stream &s, const FileSpec &f); 450 } // namespace lldb_private 451 452 namespace llvm { 453 454 /// Implementation of format_provider<T> for FileSpec. 455 /// 456 /// The options string of a FileSpec has the grammar: 457 /// 458 /// file_spec_options :: (empty) | F | D 459 /// 460 /// ======================================================= 461 /// | style | Meaning | Example | 462 /// ------------------------------------------------------- 463 /// | | | Input | Output | 464 /// ======================================================= 465 /// | F | Only print filename | /foo/bar | bar | 466 /// | D | Only print directory | /foo/bar | /foo/ | 467 /// | (empty) | Print file and dir | | | 468 /// ======================================================= 469 /// 470 /// Any other value is considered an invalid format string. 471 /// 472 template <> struct format_provider<lldb_private::FileSpec> { 473 static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream, 474 StringRef Style); 475 }; 476 477 } // namespace llvm 478 479 #endif // LLDB_UTILITY_FILESPEC_H 480