llvm.org GIT mirror llvm / c33642e
[Support] Support both Windows and Posix paths on both platforms. Previously which path syntax we supported dependend on what platform we were compiling LLVM on. While this is normally desirable, there are situations where we need to be able to handle a path that we know was generated on a remote host. Remote debugging, for example, or parsing debug info. 99% of the code in LLVM for handling paths was platform agnostic and literally just a few branches were gated behind pre-processor checks, so this changes those sites to use runtime checks instead, and adds a flag to every path API that allows one to override the host native syntax. Differential Revision: https://reviews.llvm.org/D30858 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298004 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
4 changed file(s) with 356 addition(s) and 386 deletion(s). Raw diff Collapse all Expand all
2323 namespace sys {
2424 namespace path {
2525
26 enum class Style { windows, posix, native };
27
2628 /// @name Lexical Component Iterator
2729 /// @{
2830
5052 StringRef Path; ///< The entire path.
5153 StringRef Component; ///< The current component. Not necessarily in Path.
5254 size_t Position; ///< The iterators current position within Path.
55 Style S; ///< The path style to use.
5356
5457 // An end iterator has Position = Path.size() + 1.
55 friend const_iterator begin(StringRef path);
58 friend const_iterator begin(StringRef path, Style style);
5659 friend const_iterator end(StringRef path);
5760
5861 public:
7679 StringRef Path; ///< The entire path.
7780 StringRef Component; ///< The current component. Not necessarily in Path.
7881 size_t Position; ///< The iterators current position within Path.
79
80 friend reverse_iterator rbegin(StringRef path);
82 Style S; ///< The path style to use.
83
84 friend reverse_iterator rbegin(StringRef path, Style style);
8185 friend reverse_iterator rend(StringRef path);
8286
8387 public:
9498 /// @brief Get begin iterator over \a path.
9599 /// @param path Input path.
96100 /// @returns Iterator initialized with the first component of \a path.
97 const_iterator begin(StringRef path);
101 const_iterator begin(StringRef path, Style style = Style::native);
98102
99103 /// @brief Get end iterator over \a path.
100104 /// @param path Input path.
104108 /// @brief Get reverse begin iterator over \a path.
105109 /// @param path Input path.
106110 /// @returns Iterator initialized with the first reverse component of \a path.
107 reverse_iterator rbegin(StringRef path);
111 reverse_iterator rbegin(StringRef path, Style style = Style::native);
108112
109113 /// @brief Get reverse end iterator over \a path.
110114 /// @param path Input path.
125129 /// @endcode
126130 ///
127131 /// @param path A path that is modified to not have a file component.
128 void remove_filename(SmallVectorImpl &path);
132 void remove_filename(SmallVectorImpl &path, Style style = Style::native);
129133
130134 /// @brief Replace the file extension of \a path with \a extension.
131135 ///
139143 /// @param extension The extension to be added. It may be empty. It may also
140144 /// optionally start with a '.', if it does not, one will be
141145 /// prepended.
142 void replace_extension(SmallVectorImpl &path, const Twine &extension);
146 void replace_extension(SmallVectorImpl &path, const Twine &extension,
147 Style style = Style::native);
143148
144149 /// @brief Replace matching path prefix with another path.
145150 ///
155160 /// @param OldPrefix The path prefix to strip from \a Path.
156161 /// @param NewPrefix The path prefix to replace \a NewPrefix with.
157162 void replace_path_prefix(SmallVectorImpl &Path,
158 const StringRef &OldPrefix,
159 const StringRef &NewPrefix);
163 const StringRef &OldPrefix, const StringRef &NewPrefix,
164 Style style = Style::native);
160165
161166 /// @brief Append to path.
162167 ///
173178 const Twine &c = "",
174179 const Twine &d = "");
175180
181 void append(SmallVectorImpl &path, Style style, const Twine &a,
182 const Twine &b = "", const Twine &c = "", const Twine &d = "");
183
176184 /// @brief Append to path.
177185 ///
178186 /// @code
184192 /// @param path Set to \a path + [\a begin, \a end).
185193 /// @param begin Start of components to append.
186194 /// @param end One past the end of components to append.
187 void append(SmallVectorImpl &path,
188 const_iterator begin, const_iterator end);
195 void append(SmallVectorImpl &path, const_iterator begin,
196 const_iterator end, Style style = Style::native);
189197
190198 /// @}
191199 /// @name Transforms (or some other better name)
197205 ///
198206 /// @param path A path that is transformed to native format.
199207 /// @param result Holds the result of the transformation.
200 void native(const Twine &path, SmallVectorImpl &result);
208 void native(const Twine &path, SmallVectorImpl &result,
209 Style style = Style::native);
201210
202211 /// Convert path to the native form in place. This is used to give paths to
203212 /// users and operating system calls in the platform's normal way. For example,
204213 /// on Windows all '/' are converted to '\'.
205214 ///
206215 /// @param path A path that is transformed to native format.
207 void native(SmallVectorImpl &path);
216 void native(SmallVectorImpl &path, Style style = Style::native);
208217
209218 /// @brief Replaces backslashes with slashes if Windows.
210219 ///
212221 /// @result The result of replacing backslashes with forward slashes if Windows.
213222 /// On Unix, this function is a no-op because backslashes are valid path
214223 /// chracters.
215 std::string convert_to_slash(StringRef path);
224 std::string convert_to_slash(StringRef path, Style style = Style::native);
216225
217226 /// @}
218227 /// @name Lexical Observers
228237 ///
229238 /// @param path Input path.
230239 /// @result The root name of \a path if it has one, otherwise "".
231 StringRef root_name(StringRef path);
240 StringRef root_name(StringRef path, Style style = Style::native);
232241
233242 /// @brief Get root directory.
234243 ///
241250 /// @param path Input path.
242251 /// @result The root directory of \a path if it has one, otherwise
243252 /// "".
244 StringRef root_directory(StringRef path);
253 StringRef root_directory(StringRef path, Style style = Style::native);
245254
246255 /// @brief Get root path.
247256 ///
249258 ///
250259 /// @param path Input path.
251260 /// @result The root path of \a path if it has one, otherwise "".
252 StringRef root_path(StringRef path);
261 StringRef root_path(StringRef path, Style style = Style::native);
253262
254263 /// @brief Get relative path.
255264 ///
261270 ///
262271 /// @param path Input path.
263272 /// @result The path starting after root_path if one exists, otherwise "".
264 StringRef relative_path(StringRef path);
273 StringRef relative_path(StringRef path, Style style = Style::native);
265274
266275 /// @brief Get parent path.
267276 ///
273282 ///
274283 /// @param path Input path.
275284 /// @result The parent path of \a path if one exists, otherwise "".
276 StringRef parent_path(StringRef path);
285 StringRef parent_path(StringRef path, Style style = Style::native);
277286
278287 /// @brief Get filename.
279288 ///
287296 /// @param path Input path.
288297 /// @result The filename part of \a path. This is defined as the last component
289298 /// of \a path.
290 StringRef filename(StringRef path);
299 StringRef filename(StringRef path, Style style = Style::native);
291300
292301 /// @brief Get stem.
293302 ///
305314 ///
306315 /// @param path Input path.
307316 /// @result The stem of \a path.
308 StringRef stem(StringRef path);
317 StringRef stem(StringRef path, Style style = Style::native);
309318
310319 /// @brief Get extension.
311320 ///
321330 ///
322331 /// @param path Input path.
323332 /// @result The extension of \a path.
324 StringRef extension(StringRef path);
333 StringRef extension(StringRef path, Style style = Style::native);
325334
326335 /// @brief Check whether the given char is a path separator on the host OS.
327336 ///
328337 /// @param value a character
329338 /// @result true if \a value is a path separator character on the host OS
330 bool is_separator(char value);
339 bool is_separator(char value, Style style = Style::native);
331340
332341 /// @brief Return the preferred separator for this platform.
333342 ///
334343 /// @result StringRef of the preferred separator, null-terminated.
335 StringRef get_separator();
344 StringRef get_separator(Style style = Style::native);
336345
337346 /// @brief Get the typical temporary directory for the system, e.g.,
338347 /// "/var/tmp" or "C:/TEMP"
373382 ///
374383 /// @param path Input path.
375384 /// @result True if the path has a root name, false otherwise.
376 bool has_root_name(const Twine &path);
385 bool has_root_name(const Twine &path, Style style = Style::native);
377386
378387 /// @brief Has root directory?
379388 ///
381390 ///
382391 /// @param path Input path.
383392 /// @result True if the path has a root directory, false otherwise.
384 bool has_root_directory(const Twine &path);
393 bool has_root_directory(const Twine &path, Style style = Style::native);
385394
386395 /// @brief Has root path?
387396 ///
389398 ///
390399 /// @param path Input path.
391400 /// @result True if the path has a root path, false otherwise.
392 bool has_root_path(const Twine &path);
401 bool has_root_path(const Twine &path, Style style = Style::native);
393402
394403 /// @brief Has relative path?
395404 ///
397406 ///
398407 /// @param path Input path.
399408 /// @result True if the path has a relative path, false otherwise.
400 bool has_relative_path(const Twine &path);
409 bool has_relative_path(const Twine &path, Style style = Style::native);
401410
402411 /// @brief Has parent path?
403412 ///
405414 ///
406415 /// @param path Input path.
407416 /// @result True if the path has a parent path, false otherwise.
408 bool has_parent_path(const Twine &path);
417 bool has_parent_path(const Twine &path, Style style = Style::native);
409418
410419 /// @brief Has filename?
411420 ///
413422 ///
414423 /// @param path Input path.
415424 /// @result True if the path has a filename, false otherwise.
416 bool has_filename(const Twine &path);
425 bool has_filename(const Twine &path, Style style = Style::native);
417426
418427 /// @brief Has stem?
419428 ///
421430 ///
422431 /// @param path Input path.
423432 /// @result True if the path has a stem, false otherwise.
424 bool has_stem(const Twine &path);
433 bool has_stem(const Twine &path, Style style = Style::native);
425434
426435 /// @brief Has extension?
427436 ///
429438 ///
430439 /// @param path Input path.
431440 /// @result True if the path has a extension, false otherwise.
432 bool has_extension(const Twine &path);
441 bool has_extension(const Twine &path, Style style = Style::native);
433442
434443 /// @brief Is path absolute?
435444 ///
436445 /// @param path Input path.
437446 /// @result True if the path is absolute, false if it is not.
438 bool is_absolute(const Twine &path);
447 bool is_absolute(const Twine &path, Style style = Style::native);
439448
440449 /// @brief Is path relative?
441450 ///
442451 /// @param path Input path.
443452 /// @result True if the path is relative, false if it is not.
444 bool is_relative(const Twine &path);
453 bool is_relative(const Twine &path, Style style = Style::native);
445454
446455 /// @brief Remove redundant leading "./" pieces and consecutive separators.
447456 ///
448457 /// @param path Input path.
449458 /// @result The cleaned-up \a path.
450 StringRef remove_leading_dotslash(StringRef path);
459 StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
451460
452461 /// @brief In-place remove any './' and optionally '../' components from a path.
453462 ///
455464 /// @param remove_dot_dot specify if '../' (except for leading "../") should be
456465 /// removed
457466 /// @result True if path was changed
458 bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false);
467 bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false,
468 Style style = Style::native);
459469
460470 } // end namespace path
461471 } // end namespace sys
3333 namespace {
3434 using llvm::StringRef;
3535 using llvm::sys::path::is_separator;
36
36 using llvm::sys::path::Style;
37
38 inline Style real_style(Style style) {
3739 #ifdef LLVM_ON_WIN32
38 const char *separators = "\\/";
39 const char preferred_separator = '\\';
40 return (style == Style::posix) ? Style::posix : Style::windows;
4041 #else
41 const char separators = '/';
42 const char preferred_separator = '/';
42 return (style == Style::windows) ? Style::windows : Style::posix;
4343 #endif
44
45 StringRef find_first_component(StringRef path) {
44 }
45
46 inline const char *separators(Style style) {
47 if (real_style(style) == Style::windows)
48 return "\\/";
49 return "/";
50 }
51
52 inline char preferred_separator(Style style) {
53 if (real_style(style) == Style::windows)
54 return '\\';
55 return '/';
56 }
57
58 StringRef find_first_component(StringRef path, Style style) {
4659 // Look for this first component in the following order.
4760 // * empty (in this case we return an empty string)
4861 // * either C: or {//,\\}net.
5265 if (path.empty())
5366 return path;
5467
55 #ifdef LLVM_ON_WIN32
56 // C:
57 if (path.size() >= 2 && std::isalpha(static_cast(path[0])) &&
58 path[1] == ':')
59 return path.substr(0, 2);
60 #endif
68 if (real_style(style) == Style::windows) {
69 // C:
70 if (path.size() >= 2 &&
71 std::isalpha(static_cast(path[0])) && path[1] == ':')
72 return path.substr(0, 2);
73 }
6174
6275 // //net
63 if ((path.size() > 2) &&
64 is_separator(path[0]) &&
65 path[0] == path[1] &&
66 !is_separator(path[2])) {
76 if ((path.size() > 2) && is_separator(path[0], style) &&
77 path[0] == path[1] && !is_separator(path[2], style)) {
6778 // Find the next directory separator.
68 size_t end = path.find_first_of(separators, 2);
79 size_t end = path.find_first_of(separators(style), 2);
6980 return path.substr(0, end);
7081 }
7182
7283 // {/,\}
73 if (is_separator(path[0]))
84 if (is_separator(path[0], style))
7485 return path.substr(0, 1);
7586
7687 // * {file,directory}name
77 size_t end = path.find_first_of(separators);
88 size_t end = path.find_first_of(separators(style));
7889 return path.substr(0, end);
7990 }
8091
81 size_t filename_pos(StringRef str) {
82 if (str.size() == 2 &&
83 is_separator(str[0]) &&
84 str[0] == str[1])
92 size_t filename_pos(StringRef str, Style style) {
93 if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
8594 return 0;
8695
87 if (str.size() > 0 && is_separator(str[str.size() - 1]))
96 if (str.size() > 0 && is_separator(str[str.size() - 1], style))
8897 return str.size() - 1;
8998
90 size_t pos = str.find_last_of(separators, str.size() - 1);
91
92 #ifdef LLVM_ON_WIN32
93 if (pos == StringRef::npos)
94 pos = str.find_last_of(':', str.size() - 2);
95 #endif
96
97 if (pos == StringRef::npos ||
98 (pos == 1 && is_separator(str[0])))
99 size_t pos = str.find_last_of(separators(style), str.size() - 1);
100
101 if (real_style(style) == Style::windows) {
102 if (pos == StringRef::npos)
103 pos = str.find_last_of(':', str.size() - 2);
104 }
105
106 if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
99107 return 0;
100108
101109 return pos + 1;
102110 }
103111
104 size_t root_dir_start(StringRef str) {
112 size_t root_dir_start(StringRef str, Style style) {
105113 // case "c:/"
106 #ifdef LLVM_ON_WIN32
107 if (str.size() > 2 &&
108 str[1] == ':' &&
109 is_separator(str[2]))
110 return 2;
111 #endif
114 if (real_style(style) == Style::windows) {
115 if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
116 return 2;
117 }
112118
113119 // case "//"
114 if (str.size() == 2 &&
115 is_separator(str[0]) &&
116 str[0] == str[1])
120 if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1])
117121 return StringRef::npos;
118122
119123 // case "//net"
120 if (str.size() > 3 &&
121 is_separator(str[0]) &&
122 str[0] == str[1] &&
123 !is_separator(str[2])) {
124 return str.find_first_of(separators, 2);
124 if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
125 !is_separator(str[2], style)) {
126 return str.find_first_of(separators(style), 2);
125127 }
126128
127129 // case "/"
128 if (str.size() > 0 && is_separator(str[0]))
130 if (str.size() > 0 && is_separator(str[0], style))
129131 return 0;
130132
131133 return StringRef::npos;
132134 }
133135
134 size_t parent_path_end(StringRef path) {
135 size_t end_pos = filename_pos(path);
136
137 bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
136 size_t parent_path_end(StringRef path, Style style) {
137 size_t end_pos = filename_pos(path, style);
138
139 bool filename_was_sep =
140 path.size() > 0 && is_separator(path[end_pos], style);
138141
139142 // Skip separators except for root dir.
140 size_t root_dir_pos = root_dir_start(path.substr(0, end_pos));
141
142 while(end_pos > 0 &&
143 (end_pos - 1) != root_dir_pos &&
144 is_separator(path[end_pos - 1]))
143 size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style);
144
145 while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
146 is_separator(path[end_pos - 1], style))
145147 --end_pos;
146148
147149 if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
229231 namespace sys {
230232 namespace path {
231233
232 const_iterator begin(StringRef path) {
234 const_iterator begin(StringRef path, Style style) {
233235 const_iterator i;
234236 i.Path = path;
235 i.Component = find_first_component(path);
237 i.Component = find_first_component(path, style);
236238 i.Position = 0;
239 i.S = style;
237240 return i;
238241 }
239242
258261
259262 // Both POSIX and Windows treat paths that begin with exactly two separators
260263 // specially.
261 bool was_net = Component.size() > 2 &&
262 is_separator(Component[0]) &&
263 Component[1] == Component[0] &&
264 !is_separator(Component[2]);
264 bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
265 Component[1] == Component[0] && !is_separator(Component[2], S);
265266
266267 // Handle separators.
267 if (is_separator(Path[Position])) {
268 if (is_separator(Path[Position], S)) {
268269 // Root dir.
269 if (was_net
270 #ifdef LLVM_ON_WIN32
270 if (was_net ||
271271 // c:/
272 || Component.endswith(":")
273 #endif
274 ) {
272 (real_style(S) == Style::windows && Component.endswith(":"))) {
275273 Component = Path.substr(Position, 1);
276274 return *this;
277275 }
278276
279277 // Skip extra separators.
280 while (Position != Path.size() &&
281 is_separator(Path[Position])) {
278 while (Position != Path.size() && is_separator(Path[Position], S)) {
282279 ++Position;
283280 }
284281
291288 }
292289
293290 // Find next component.
294 size_t end_pos = Path.find_first_of(separators, Position);
291 size_t end_pos = Path.find_first_of(separators(S), Position);
295292 Component = Path.slice(Position, end_pos);
296293
297294 return *this;
305302 return Position - RHS.Position;
306303 }
307304
308 reverse_iterator rbegin(StringRef Path) {
305 reverse_iterator rbegin(StringRef Path, Style style) {
309306 reverse_iterator I;
310307 I.Path = Path;
311308 I.Position = Path.size();
309 I.S = style;
312310 return ++I;
313311 }
314312
323321 reverse_iterator &reverse_iterator::operator++() {
324322 // If we're at the end and the previous char was a '/', return '.' unless
325323 // we are the root path.
326 size_t root_dir_pos = root_dir_start(Path);
327 if (Position == Path.size() &&
328 Path.size() > root_dir_pos + 1 &&
329 is_separator(Path[Position - 1])) {
324 size_t root_dir_pos = root_dir_start(Path, S);
325 if (Position == Path.size() && Path.size() > root_dir_pos + 1 &&
326 is_separator(Path[Position - 1], S)) {
330327 --Position;
331328 Component = ".";
332329 return *this;
335332 // Skip separators unless it's the root directory.
336333 size_t end_pos = Position;
337334
338 while(end_pos > 0 &&
339 (end_pos - 1) != root_dir_pos &&
340 is_separator(Path[end_pos - 1]))
335 while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
336 is_separator(Path[end_pos - 1], S))
341337 --end_pos;
342338
343339 // Find next separator.
344 size_t start_pos = filename_pos(Path.substr(0, end_pos));
340 size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
345341 Component = Path.slice(start_pos, end_pos);
346342 Position = start_pos;
347343 return *this;
356352 return Position - RHS.Position;
357353 }
358354
359 StringRef root_path(StringRef path) {
360 const_iterator b = begin(path),
361 pos = b,
362 e = end(path);
355 StringRef root_path(StringRef path, Style style) {
356 const_iterator b = begin(path, style), pos = b, e = end(path);
363357 if (b != e) {
364 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
365 bool has_drive =
366 #ifdef LLVM_ON_WIN32
367 b->endswith(":");
368 #else
369 false;
370 #endif
358 bool has_net =
359 b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
360 bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
371361
372362 if (has_net || has_drive) {
373 if ((++pos != e) && is_separator((*pos)[0])) {
363 if ((++pos != e) && is_separator((*pos)[0], style)) {
374364 // {C:/,//net/}, so get the first two components.
375365 return path.substr(0, b->size() + pos->size());
376366 } else {
380370 }
381371
382372 // POSIX style root directory.
383 if (is_separator((*b)[0])) {
373 if (is_separator((*b)[0], style)) {
384374 return *b;
385375 }
386376 }
388378 return StringRef();
389379 }
390380
391 StringRef root_name(StringRef path) {
392 const_iterator b = begin(path),
393 e = end(path);
381 StringRef root_name(StringRef path, Style style) {
382 const_iterator b = begin(path, style), e = end(path);
394383 if (b != e) {
395 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
396 bool has_drive =
397 #ifdef LLVM_ON_WIN32
398 b->endswith(":");
399 #else
400 false;
401 #endif
384 bool has_net =
385 b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
386 bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
402387
403388 if (has_net || has_drive) {
404389 // just {C:,//net}, return the first component.
410395 return StringRef();
411396 }
412397
413 StringRef root_directory(StringRef path) {
414 const_iterator b = begin(path),
415 pos = b,
416 e = end(path);
398 StringRef root_directory(StringRef path, Style style) {
399 const_iterator b = begin(path, style), pos = b, e = end(path);
417400 if (b != e) {
418 bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
419 bool has_drive =
420 #ifdef LLVM_ON_WIN32
421 b->endswith(":");
422 #else
423 false;
424 #endif
401 bool has_net =
402 b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
403 bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
425404
426405 if ((has_net || has_drive) &&
427406 // {C:,//net}, skip to the next component.
428 (++pos != e) && is_separator((*pos)[0])) {
407 (++pos != e) && is_separator((*pos)[0], style)) {
429408 return *pos;
430409 }
431410
432411 // POSIX style root directory.
433 if (!has_net && is_separator((*b)[0])) {
412 if (!has_net && is_separator((*b)[0], style)) {
434413 return *b;
435414 }
436415 }
439418 return StringRef();
440419 }
441420
442 StringRef relative_path(StringRef path) {
443 StringRef root = root_path(path);
421 StringRef relative_path(StringRef path, Style style) {
422 StringRef root = root_path(path, style);
444423 return path.substr(root.size());
445424 }
446425
447 void append(SmallVectorImpl &path, const Twine &a,
448 const Twine &b,
449 const Twine &c,
450 const Twine &d) {
426 void append(SmallVectorImpl &path, Style style, const Twine &a,
427 const Twine &b, const Twine &c, const Twine &d) {
451428 SmallString<32> a_storage;
452429 SmallString<32> b_storage;
453430 SmallString<32> c_storage;
460437 if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
461438
462439 for (auto &component : components) {
463 bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
464 bool component_has_sep = !component.empty() && is_separator(component[0]);
465 bool is_root_name = has_root_name(component);
440 bool path_has_sep =
441 !path.empty() && is_separator(path[path.size() - 1], style);
442 bool component_has_sep =
443 !component.empty() && is_separator(component[0], style);
444 bool is_root_name = has_root_name(component, style);
466445
467446 if (path_has_sep) {
468447 // Strip separators from beginning of component.
469 size_t loc = component.find_first_not_of(separators);
448 size_t loc = component.find_first_not_of(separators(style));
470449 StringRef c = component.substr(loc);
471450
472451 // Append it.
476455
477456 if (!component_has_sep && !(path.empty() || is_root_name)) {
478457 // Add a separator.
479 path.push_back(preferred_separator);
458 path.push_back(preferred_separator(style));
480459 }
481460
482461 path.append(component.begin(), component.end());
483462 }
484463 }
485464
486 void append(SmallVectorImpl &path,
487 const_iterator begin, const_iterator end) {
465 void append(SmallVectorImpl &path, const Twine &a, const Twine &b,
466 const Twine &c, const Twine &d) {
467 append(path, Style::native, a, b, c, d);
468 }
469
470 void append(SmallVectorImpl &path, const_iterator begin,
471 const_iterator end, Style style) {
488472 for (; begin != end; ++begin)
489 path::append(path, *begin);
490 }
491
492 StringRef parent_path(StringRef path) {
493 size_t end_pos = parent_path_end(path);
473 path::append(path, style, *begin);
474 }
475
476 StringRef parent_path(StringRef path, Style style) {
477 size_t end_pos = parent_path_end(path, style);
494478 if (end_pos == StringRef::npos)
495479 return StringRef();
496480 else
497481 return path.substr(0, end_pos);
498482 }
499483
500 void remove_filename(SmallVectorImpl &path) {
501 size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
484 void remove_filename(SmallVectorImpl &path, Style style) {
485 size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
502486 if (end_pos != StringRef::npos)
503487 path.set_size(end_pos);
504488 }
505489
506 void replace_extension(SmallVectorImpl &path, const Twine &extension) {
490 void replace_extension(SmallVectorImpl &path, const Twine &extension,
491 Style style) {
507492 StringRef p(path.begin(), path.size());
508493 SmallString<32> ext_storage;
509494 StringRef ext = extension.toStringRef(ext_storage);
510495
511496 // Erase existing extension.
512497 size_t pos = p.find_last_of('.');
513 if (pos != StringRef::npos && pos >= filename_pos(p))
498 if (pos != StringRef::npos && pos >= filename_pos(p, style))
514499 path.set_size(pos);
515500
516501 // Append '.' if needed.
522507 }
523508
524509 void replace_path_prefix(SmallVectorImpl &Path,
525 const StringRef &OldPrefix,
526 const StringRef &NewPrefix) {
510 const StringRef &OldPrefix, const StringRef &NewPrefix,
511 Style style) {
527512 if (OldPrefix.empty() && NewPrefix.empty())
528513 return;
529514
539524
540525 StringRef RelPath = OrigPath.substr(OldPrefix.size());
541526 SmallString<256> NewPath;
542 path::append(NewPath, NewPrefix);
543 path::append(NewPath, RelPath);
527 path::append(NewPath, style, NewPrefix);
528 path::append(NewPath, style, RelPath);
544529 Path.swap(NewPath);
545530 }
546531
547 void native(const Twine &path, SmallVectorImpl &result) {
532 void native(const Twine &path, SmallVectorImpl &result, Style style) {
548533 assert((!path.isSingleStringRef() ||
549534 path.getSingleStringRef().data() != result.data()) &&
550535 "path and result are not allowed to overlap!");
551536 // Clear result.
552537 result.clear();
553538 path.toVector(result);
554 native(result);
555 }
556
557 void native(SmallVectorImpl &Path) {
539 native(result, style);
540 }
541
542 void native(SmallVectorImpl &Path, Style style) {
558543 if (Path.empty())
559544 return;
560 #ifdef LLVM_ON_WIN32
561 std::replace(Path.begin(), Path.end(), '/', '\\');
562 if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1]))) {
563 SmallString<128> PathHome;
564 home_directory(PathHome);
565 PathHome.append(Path.begin() + 1, Path.end());
566 Path = PathHome;
567 }
568 #else
569 for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
570 if (*PI == '\\') {
571 auto PN = PI + 1;
572 if (PN < PE && *PN == '\\')
573 ++PI; // increment once, the for loop will move over the escaped slash
574 else
575 *PI = '/';
576 }
577 }
578 #endif
579 }
580
581 std::string convert_to_slash(StringRef path) {
582 #ifdef LLVM_ON_WIN32
545 if (real_style(style) == Style::windows) {
546 std::replace(Path.begin(), Path.end(), '/', '\\');
547 if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
548 SmallString<128> PathHome;
549 home_directory(PathHome);
550 PathHome.append(Path.begin() + 1, Path.end());
551 Path = PathHome;
552 }
553 } else {
554 for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
555 if (*PI == '\\') {
556 auto PN = PI + 1;
557 if (PN < PE && *PN == '\\')
558 ++PI; // increment once, the for loop will move over the escaped slash
559 else
560 *PI = '/';
561 }
562 }
563 }
564 }
565
566 std::string convert_to_slash(StringRef path, Style style) {
567 if (real_style(style) != Style::windows)
568 return path;
569
583570 std::string s = path.str();
584571 std::replace(s.begin(), s.end(), '\\', '/');
585572 return s;
586 #else
587 return path;
588 #endif
589 }
590
591 StringRef filename(StringRef path) {
592 return *rbegin(path);
593 }
594
595 StringRef stem(StringRef path) {
596 StringRef fname = filename(path);
573 }
574
575 StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
576
577 StringRef stem(StringRef path, Style style) {
578 StringRef fname = filename(path, style);
597579 size_t pos = fname.find_last_of('.');
598580 if (pos == StringRef::npos)
599581 return fname;
605587 return fname.substr(0, pos);
606588 }
607589
608 StringRef extension(StringRef path) {
609 StringRef fname = filename(path);
590 StringRef extension(StringRef path, Style style) {
591 StringRef fname = filename(path, style);
610592 size_t pos = fname.find_last_of('.');
611593 if (pos == StringRef::npos)
612594 return StringRef();
618600 return fname.substr(pos);
619601 }
620602
621 bool is_separator(char value) {
622 switch(value) {
623 #ifdef LLVM_ON_WIN32
624 case '\\': // fall through
625 #endif
626 case '/': return true;
627 default: return false;
628 }
629 }
630
631 static const char preferred_separator_string[] = { preferred_separator, '\0' };
632
633 StringRef get_separator() {
634 return preferred_separator_string;
635 }
636
637 bool has_root_name(const Twine &path) {
603 bool is_separator(char value, Style style) {
604 if (value == '/')
605 return true;
606 if (real_style(style) == Style::windows)
607 return value == '\\';
608 return false;
609 }
610
611 StringRef get_separator(Style style) {
612 if (real_style(style) == Style::windows)
613 return "\\";
614 return "/";
615 }
616
617 bool has_root_name(const Twine &path, Style style) {
638618 SmallString<128> path_storage;
639619 StringRef p = path.toStringRef(path_storage);
640620
641 return !root_name(p).empty();
642 }
643
644 bool has_root_directory(const Twine &path) {
621 return !root_name(p, style).empty();
622 }
623
624 bool has_root_directory(const Twine &path, Style style) {
645625 SmallString<128> path_storage;
646626 StringRef p = path.toStringRef(path_storage);
647627
648 return !root_directory(p).empty();
649 }
650
651 bool has_root_path(const Twine &path) {
628 return !root_directory(p, style).empty();
629 }
630
631 bool has_root_path(const Twine &path, Style style) {
652632 SmallString<128> path_storage;
653633 StringRef p = path.toStringRef(path_storage);
654634
655 return !root_path(p).empty();
656 }
657
658 bool has_relative_path(const Twine &path) {
635 return !root_path(p, style).empty();
636 }
637
638 bool has_relative_path(const Twine &path, Style style) {
659639 SmallString<128> path_storage;
660640 StringRef p = path.toStringRef(path_storage);
661641
662 return !relative_path(p).empty();
663 }
664
665 bool has_filename(const Twine &path) {
642 return !relative_path(p, style).empty();
643 }
644
645 bool has_filename(const Twine &path, Style style) {
666646 SmallString<128> path_storage;
667647 StringRef p = path.toStringRef(path_storage);
668648
669 return !filename(p).empty();
670 }
671
672 bool has_parent_path(const Twine &path) {
649 return !filename(p, style).empty();
650 }
651
652 bool has_parent_path(const Twine &path, Style style) {
673653 SmallString<128> path_storage;
674654 StringRef p = path.toStringRef(path_storage);
675655
676 return !parent_path(p).empty();
677 }
678
679 bool has_stem(const Twine &path) {
656 return !parent_path(p, style).empty();
657 }
658
659 bool has_stem(const Twine &path, Style style) {
680660 SmallString<128> path_storage;
681661 StringRef p = path.toStringRef(path_storage);
682662
683 return !stem(p).empty();
684 }
685
686 bool has_extension(const Twine &path) {
663 return !stem(p, style).empty();
664 }
665
666 bool has_extension(const Twine &path, Style style) {
687667 SmallString<128> path_storage;
688668 StringRef p = path.toStringRef(path_storage);
689669
690 return !extension(p).empty();
691 }
692
693 bool is_absolute(const Twine &path) {
670 return !extension(p, style).empty();
671 }
672
673 bool is_absolute(const Twine &path, Style style) {
694674 SmallString<128> path_storage;
695675 StringRef p = path.toStringRef(path_storage);
696676
697 bool rootDir = has_root_directory(p),
698 #ifdef LLVM_ON_WIN32
699 rootName = has_root_name(p);
700 #else
701 rootName = true;
702 #endif
677 bool rootDir = has_root_directory(p, style);
678 bool rootName =
679 (real_style(style) != Style::windows) || has_root_name(p, style);
703680
704681 return rootDir && rootName;
705682 }
706683
707 bool is_relative(const Twine &path) { return !is_absolute(path); }
708
709 StringRef remove_leading_dotslash(StringRef Path) {
684 bool is_relative(const Twine &path, Style style) {
685 return !is_absolute(path, style);
686 }
687
688 StringRef remove_leading_dotslash(StringRef Path, Style style) {
710689 // Remove leading "./" (or ".//" or "././" etc.)
711 while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) {
690 while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
712691 Path = Path.substr(2);
713 while (Path.size() > 0 && is_separator(Path[0]))
692 while (Path.size() > 0 && is_separator(Path[0], style))
714693 Path = Path.substr(1);
715694 }
716695 return Path;
717696 }
718697
719 static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
698 static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
699 Style style) {
720700 SmallVector components;
721701
722702 // Skip the root path, then look for traversal in the components.
723 StringRef rel = path::relative_path(path);
724 for (StringRef C : llvm::make_range(path::begin(rel), path::end(rel))) {
703 StringRef rel = path::relative_path(path, style);
704 for (StringRef C :
705 llvm::make_range(path::begin(rel, style), path::end(rel))) {
725706 if (C == ".")
726707 continue;
727708 // Leading ".." will remain in the path unless it's at the root.
730711 components.pop_back();
731712 continue;
732713 }
733 if (path::is_absolute(path))
714 if (path::is_absolute(path, style))
734715 continue;
735716 }
736717 components.push_back(C);
737718 }
738719
739 SmallString<256> buffer = path::root_path(path);
720 SmallString<256> buffer = path::root_path(path, style);
740721 for (StringRef C : components)
741 path::append(buffer, C);
722 path::append(buffer, style, C);
742723 return buffer;
743724 }
744725
745 bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot) {
726 bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot,
727 Style style) {
746728 StringRef p(path.data(), path.size());
747729
748 SmallString<256> result = remove_dots(p, remove_dot_dot);
730 SmallString<256> result = remove_dots(p, remove_dot_dot, style);
749731 if (result == path)
750732 return false;
751733
783765 llvm::SmallVectorImpl &ResultPath, FSEntity Type) {
784766 SmallString<128> Storage;
785767 StringRef P = Model.toNullTerminatedStringRef(Storage);
786 assert(P.find_first_of(separators) == StringRef::npos &&
768 assert(P.find_first_of(separators(Style::native)) == StringRef::npos &&
787769 "Model must be a simple filename.");
788770 // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
789771 return createUniqueEntity(P.begin(), ResultFD, ResultPath,
825807 bool use_current_directory) {
826808 StringRef p(path.data(), path.size());
827809
828 bool rootDirectory = path::has_root_directory(p),
829 #ifdef LLVM_ON_WIN32
830 rootName = path::has_root_name(p);
831 #else
832 rootName = true;
833 #endif
810 bool rootDirectory = path::has_root_directory(p);
811 bool rootName =
812 (real_style(Style::native) != Style::windows) || path::has_root_name(p);
834813
835814 // Already absolute.
836815 if (rootName && rootDirectory)
10221022
10231023 StringRef PathStr(Path.begin(), Path.size());
10241024 PathStr = PathStr.drop_front();
1025 StringRef Expr = PathStr.take_until(path::is_separator);
1025 StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); });
10261026
10271027 if (!Expr.empty()) {
10281028 // This is probably a ~username/ expression. Don't support this on Windows.
5252 EXPECT_FALSE(path::is_separator('-'));
5353 EXPECT_FALSE(path::is_separator(' '));
5454
55 EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
56 EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
57
5558 #ifdef LLVM_ON_WIN32
5659 EXPECT_TRUE(path::is_separator('\\'));
5760 #else
58 EXPECT_FALSE(path::is_separator('\\'));
61 EXPECT_FALSE(path::is_separator('\\', ));
5962 #endif
6063 }
6164
251254 }
252255 }
253256
254 #ifdef LLVM_ON_WIN32
255257 TEST(Support, AbsolutePathIteratorWin32) {
256258 SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt"));
257259 typedef SmallVector PathComponents;
264266 // when iterating.
265267 ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\");
266268
267 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E;
268 ++I) {
269 for (path::const_iterator I = path::begin(Path, path::Style::windows),
270 E = path::end(Path);
271 I != E; ++I) {
269272 ActualPathComponents.push_back(*I);
270273 }
271274
275278 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str());
276279 }
277280 }
278 #endif // LLVM_ON_WIN32
279281
280282 TEST(Support, AbsolutePathIteratorEnd) {
281283 // Trailing slashes are converted to '.' unless they are part of the root path.
282 SmallVector Paths;
283 Paths.push_back("/foo/");
284 Paths.push_back("/foo//");
285 Paths.push_back("//net//");
286 #ifdef LLVM_ON_WIN32
287 Paths.push_back("c:\\\\");
288 #endif
289
290 for (StringRef Path : Paths) {
291 StringRef LastComponent = *path::rbegin(Path);
284 SmallVector, 4> Paths;
285 Paths.emplace_back("/foo/", path::Style::native);
286 Paths.emplace_back("/foo//", path::Style::native);
287 Paths.emplace_back("//net//", path::Style::native);
288 Paths.emplace_back("c:\\\\", path::Style::windows);
289
290 for (auto &Path : Paths) {
291 StringRef LastComponent = *path::rbegin(Path.first, Path.second);
292292 EXPECT_EQ(".", LastComponent);
293293 }
294294
295 SmallVector RootPaths;
296 RootPaths.push_back("/");
297 RootPaths.push_back("//net/");
298 #ifdef LLVM_ON_WIN32
299 RootPaths.push_back("c:\\");
300 #endif
301
302 for (StringRef Path : RootPaths) {
303 StringRef LastComponent = *path::rbegin(Path);
295 SmallVector, 3> RootPaths;
296 RootPaths.emplace_back("/", path::Style::native);
297 RootPaths.emplace_back("//net/", path::Style::native);
298 RootPaths.emplace_back("c:\\", path::Style::windows);
299
300 for (auto &Path : RootPaths) {
301 StringRef LastComponent = *path::rbegin(Path.first, Path.second);
304302 EXPECT_EQ(1u, LastComponent.size());
305 EXPECT_TRUE(path::is_separator(LastComponent[0]));
303 EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));
306304 }
307305 }
308306
10551053 }
10561054
10571055 TEST(Support, NormalizePath) {
1058 #if defined(LLVM_ON_WIN32)
1059 #define EXPECT_PATH_IS(path__, windows__, not_windows__) \
1060 EXPECT_EQ(path__, windows__);
1061 #else
1062 #define EXPECT_PATH_IS(path__, windows__, not_windows__) \
1063 EXPECT_EQ(path__, not_windows__);
1064 #endif
1065
1066 SmallString<64> Path1("a");
1067 SmallString<64> Path2("a/b");
1068 SmallString<64> Path3("a\\b");
1069 SmallString<64> Path4("a\\\\b");
1070 SmallString<64> Path5("\\a");
1071 SmallString<64> Path6("a\\");
1072
1073 path::native(Path1);
1074 EXPECT_PATH_IS(Path1, "a", "a");
1075
1076 path::native(Path2);
1077 EXPECT_PATH_IS(Path2, "a\\b", "a/b");
1078
1079 path::native(Path3);
1080 EXPECT_PATH_IS(Path3, "a\\b", "a/b");
1081
1082 path::native(Path4);
1083 EXPECT_PATH_IS(Path4, "a\\\\b", "a\\\\b");
1084
1085 path::native(Path5);
1086 EXPECT_PATH_IS(Path5, "\\a", "/a");
1087
1088 path::native(Path6);
1089 EXPECT_PATH_IS(Path6, "a\\", "a/");
1090
1091 #undef EXPECT_PATH_IS
1056 using TestTuple = std::tuple;
1057 TestTuple Tests[] = {{"a", "a", "a"}, {"a/b", "a\\b", "a/b"},
1058 {"a\\b", "a\\b", "a/b"}, {"a\\\\b", "a\\\\b", "a\\\\b"},
1059 {"\\a", "\\a", "/a"}, {"a\\", "a\\", "a/"}};
1060 for (auto &T : Tests) {
1061 SmallString<64> Win = std::get<0>(T);
1062 SmallString<64> Posix = Win;
1063 path::native(Win, path::Style::windows);
1064 path::native(Posix, path::Style::posix);
1065 EXPECT_EQ(std::get<1>(T), Win);
1066 EXPECT_EQ(std::get<2>(T), Posix);
1067 }
10921068
10931069 #if defined(LLVM_ON_WIN32)
10941070 SmallString<64> PathHome;
11281104 EXPECT_EQ(Path2, "");
11291105 }
11301106
1131 static std::string remove_dots(StringRef path,
1132 bool remove_dot_dot) {
1107 static std::string remove_dots(StringRef path, bool remove_dot_dot,
1108 path::Style style) {
11331109 SmallString<256> buffer(path);
1134 path::remove_dots(buffer, remove_dot_dot);
1110 path::remove_dots(buffer, remove_dot_dot, style);
11351111 return buffer.str();
11361112 }
11371113
11381114 TEST(Support, RemoveDots) {
1139 #if defined(LLVM_ON_WIN32)
1140 EXPECT_EQ("foolz\\wat", remove_dots(".\\.\\\\foolz\\wat", false));
1141 EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false));
1142
1143 EXPECT_EQ("a\\..\\b\\c", remove_dots(".\\a\\..\\b\\c", false));
1144 EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true));
1145 EXPECT_EQ("c", remove_dots(".\\.\\c", true));
1146 EXPECT_EQ("..\\a\\c", remove_dots("..\\a\\b\\..\\c", true));
1147 EXPECT_EQ("..\\..\\a\\c", remove_dots("..\\..\\a\\b\\..\\c", true));
1115 EXPECT_EQ("foolz\\wat",
1116 remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));
1117 EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));
1118
1119 EXPECT_EQ("a\\..\\b\\c",
1120 remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));
1121 EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));
1122 EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));
1123 EXPECT_EQ("..\\a\\c",
1124 remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));
1125 EXPECT_EQ("..\\..\\a\\c",
1126 remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));
11481127
11491128 SmallString<64> Path1(".\\.\\c");
1150 EXPECT_TRUE(path::remove_dots(Path1, true));
1129 EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));
11511130 EXPECT_EQ("c", Path1);
1152 #else
1153 EXPECT_EQ("foolz/wat", remove_dots("././/foolz/wat", false));
1154 EXPECT_EQ("", remove_dots("./////", false));
1155
1156 EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false));
1157 EXPECT_EQ("b/c", remove_dots("./a/../b/c", true));
1158 EXPECT_EQ("c", remove_dots("././c", true));
1159 EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true));
1160 EXPECT_EQ("../../a/c", remove_dots("../../a/b/../c", true));
1161 EXPECT_EQ("/a/c", remove_dots("/../../a/c", true));
1162 EXPECT_EQ("/a/c", remove_dots("/../a/b//../././/c", true));
1163
1164 SmallString<64> Path1("././c");
1165 EXPECT_TRUE(path::remove_dots(Path1, true));
1166 EXPECT_EQ("c", Path1);
1167 #endif
1131
1132 EXPECT_EQ("foolz/wat",
1133 remove_dots("././/foolz/wat", false, path::Style::posix));
1134 EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));
1135
1136 EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));
1137 EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));
1138 EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));
1139 EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));
1140 EXPECT_EQ("../../a/c",
1141 remove_dots("../../a/b/../c", true, path::Style::posix));
1142 EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));
1143 EXPECT_EQ("/a/c",
1144 remove_dots("/../a/b//../././/c", true, path::Style::posix));
1145
1146 SmallString<64> Path2("././c");
1147 EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));
1148 EXPECT_EQ("c", Path2);
11681149 }
11691150
11701151 TEST(Support, ReplacePathPrefix) {