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