1 //
2 // CDDL HEADER START
3 //
4 // The contents of this file are subject to the terms of the Common Development
5 // and Distribution License Version 1.0 (the "License").
6 //
7 // You can obtain a copy of the license at
8 // http://www.opensource.org/licenses/CDDL-1.0.  See the License for the
9 // specific language governing permissions and limitations under the License.
10 //
11 // When distributing Covered Code, include this CDDL HEADER in each file and
12 // include the License file in a prominent location with the name LICENSE.CDDL.
13 // If applicable, add the following below this CDDL HEADER, with the fields
14 // enclosed by brackets "[]" replaced with your own identifying information:
15 //
16 // Portions Copyright (c) [yyyy] [name of copyright owner]. All rights reserved.
17 //
18 // CDDL HEADER END
19 //
20 
21 //
22 // Copyright (c) 2016--2020, Regents of the University of Minnesota.
23 // All rights reserved.
24 //
25 // Contributors:
26 //    Ryan S. Elliott
27 //    Alexander Stukowski
28 //
29 
30 //
31 // Release: This file is part of the kim-api-2.2.1 package.
32 //
33 
34 
35 #ifndef KIM_FILESYSTEM_PATH_HPP_
36 #define KIM_FILESYSTEM_PATH_HPP_
37 
38 #include <cstdlib>
39 #include <iostream>
40 #include <vector>
41 
42 // If available, use the std::filesystem::path class
43 // for cross-platform file path handling introduced with C++17.
44 // Older versions of the GCC compiler support C++17 but do not include an
45 // implementation of the std::filesystem library. Then fall back to the GHC
46 // drop-in replacement library. In all other cases, in particular in C++98 mode,
47 // fall back to a minimal implementation based on std::string.
48 #if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
49 // C++17 mode:
50 #if __has_include(<filesystem>)
51 // Have std::filesystem implementation:
52 #include <filesystem>
53 #else
54 // Fall back to drop-in library:
55 #define GHC_WIN_WSTRING_STRING_TYPE
56 #include "ghc-filesystem/filesystem.hpp"
57 // We need the alias from ghc::filesystem to std::filesystem
58 namespace std
59 {
60 namespace filesystem = ghc::filesystem;
61 }
62 #endif
63 #define KIM_API_USE_FILESYSTEM_LIBRARY 1
64 #endif
65 
66 #ifdef KIM_API_USE_FILESYSTEM_LIBRARY
67 namespace
68 {
69 typedef std::filesystem::path KIM_Path;
70 }
71 #else
72 #include <string>
73 namespace
74 {
75 typedef std::string KIM_Path;
76 }
77 #endif
78 
79 namespace KIM
80 {
81 namespace FILESYSTEM
82 {
83 class Path
84 {
85  public:
86   // Platform-dependent character for separating path entries.
87   static const std::string::value_type preferred_separator;
88 
Path()89   Path() {}
Path(const char * str)90   Path(const char * str)
91   {
92     if (str != NULL) path_ = str;
93   }
Path(const std::string & str)94   Path(const std::string & str) : path_(str) {}
95 #ifdef KIM_API_USE_FILESYSTEM_LIBRARY
Path(const std::filesystem::path & p)96   Path(const std::filesystem::path & p) : path_(p) {}
Path(std::filesystem::path && p)97   Path(std::filesystem::path && p) : path_(std::move(p)) {}
98 #endif
99 
operator =(const std::string & other)100   Path & operator=(const std::string & other)
101   {
102     path_ = other;
103     return *this;
104   }
105 
operator =(const char * other)106   Path & operator=(const char * other)
107   {
108     path_ = other;
109     return *this;
110   }
111 
112   Path & operator+=(char const * const s);
113   Path & operator/=(const Path & p);
114   Path operator/(const Path & p) const;
operator <(const Path & lhs,const Path & rhs)115   friend bool operator<(const Path & lhs, const Path & rhs)
116   {
117     return lhs.path_ < rhs.path_;
118   }
operator ==(const Path & lhs,const Path & rhs)119   friend bool operator==(const Path & lhs, const Path & rhs)
120   {
121     return lhs.path_ == rhs.path_;
122   }
123 
124   // Concatenates the current path and the argument.
125   Path & concat(const std::string & p);
126 
127   // Turns the path object into a conventional string, which can be passed to
128   // I/O functions.
129   std::string string() const;
130 
131   // Returns the native string representation of the path, using native syntax,
132   // native character type, and native character encoding. This string is
133   // suitable for use with OS APIs.
c_str() const134   const KIM_Path::value_type * c_str() const { return path_.c_str(); }
135 
136   // Resets the path to an empty string.
clear()137   void clear() { path_.clear(); }
138 
139   // Returns whether this path is the empty string.
empty() const140   bool empty() const { return path_.empty(); }
141 
142   // Returns the path of the parent path
143   Path parent_path() const;
144 
145   // Returns the last component of the path.
146   Path filename() const;
147 
148   // Removes a single filename component from the path.
149   Path & remove_filename();
150 
151   // Converts all directory separators to the preferred directory separator of
152   // the current platform.
153   Path & make_preferred();
154 
155   // Creates a new directory, including parent directories if necessary.
156   // It's not an error if the directory to be created already exists.
157   // Returns true on error.
158   bool MakeDirectory() const;
159 
160   // Deletes the contents of this path (if it is a directory) and the contents
161   // of all its subdirectories, recursively, then deletes the file path itself.
162   // Returns true on error.
163   bool RemoveDirectoryRecursive() const;
164 
165   // Returns the list of subdirectories of this directory.
166   std::vector<Path> Subdirectories() const;
167 
168   // Checks whether the file or directory exists.
169   bool exists() const;
170 
171   // Checks whether the path is relative.
172   bool is_relative() const;
173 
174   // Returns the current working directory.
175   static Path current_path();
176 
177   // Returns the user's home directory.
178   static Path HomePath();
179 
180   // Creates a new empty directory that can be used to write temporary files
181   // into. Returns an empty path on failure.
182   static Path CreateTemporaryDirectory(char const * const namePrefix);
183 
184   // Performs stream output on the path (operator <<).
185   template<class CharT, class Traits>
186   friend std::basic_ostream<CharT, Traits> &
operator <<(std::basic_ostream<CharT,Traits> & os,const Path & p)187   operator<<(std::basic_ostream<CharT, Traits> & os, const Path & p)
188   {
189     return os << p.path_;
190   }
191 
192  private:
193   // The internal path storage:
194   KIM_Path path_;
195 };
196 
197 class PathList : public std::vector<Path>
198 {
199  public:
200   // Platform-dependent character for separating paths in the lists.
201   static const std::string::value_type PreferredSeparator;
202 
203   // Platform-dependent character for home directory.
204   static const std::string::value_type HomeDirectoryShortcut;
205 
206   // Creates all directories in the path list, including parent directories if
207   // necessary. It's not an error if a directory to be created already exists.
208   // Returns true on error.
209   bool MakeDirectories() const;
210 
211   // Converts the path list into a colon- or semicolon-separated string list.
212   std::string ToString() const;
213 
214   // Parses a list of filesystem paths separated by colons (or semi-colons on
215   // Windows).
216   // '~' at the beginning of a path is replaced with the user's home directory.
217   size_t Parse(std::string::value_type const * const paths);
218 
219   // Performs stream output on the path (operator <<).
220   template<class CharT, class Traits>
221   friend std::basic_ostream<CharT, Traits> &
operator <<(std::basic_ostream<CharT,Traits> & os,const PathList & p)222   operator<<(std::basic_ostream<CharT, Traits> & os, const PathList & p)
223   {
224     return os << p.ToString();
225   }
226 };
227 
228 }  // namespace FILESYSTEM
229 }  // namespace KIM
230 
231 #endif  // KIM_FILESYSTEM_PATH_HPP_
232