annotate libphobos/src/std/path.d @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1 // Written in the D programming language.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3 /** This module is used to manipulate _path strings.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
5 All functions, with the exception of $(LREF expandTilde) (and in some
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
6 cases $(LREF absolutePath) and $(LREF relativePath)), are pure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
7 string manipulation functions; they don't depend on any state outside
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
8 the program, nor do they perform any actual file system actions.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
9 This has the consequence that the module does not make any distinction
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
10 between a _path that points to a directory and a _path that points to a
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
11 file, and it does not know whether or not the object pointed to by the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
12 _path actually exists in the file system.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
13 To differentiate between these cases, use $(REF isDir, std,file) and
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
14 $(REF exists, std,file).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
15
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
16 Note that on Windows, both the backslash ($(D `\`)) and the slash ($(D `/`))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
17 are in principle valid directory separators. This module treats them
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
18 both on equal footing, but in cases where a $(I new) separator is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
19 added, a backslash will be used. Furthermore, the $(LREF buildNormalizedPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
20 function will replace all slashes with backslashes on that platform.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
21
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
22 In general, the functions in this module assume that the input paths
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
23 are well-formed. (That is, they should not contain invalid characters,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
24 they should follow the file system's _path format, etc.) The result
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
25 of calling a function on an ill-formed _path is undefined. When there
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
26 is a chance that a _path or a file name is invalid (for instance, when it
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
27 has been input by the user), it may sometimes be desirable to use the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
28 $(LREF isValidFilename) and $(LREF isValidPath) functions to check
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
29 this.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
30
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
31 Most functions do not perform any memory allocations, and if a string is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
32 returned, it is usually a slice of an input string. If a function
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
33 allocates, this is explicitly mentioned in the documentation.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
34
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
35 $(SCRIPT inhibitQuickIndex = 1;)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
36 $(DIVC quickindex,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
37 $(BOOKTABLE,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
38 $(TR $(TH Category) $(TH Functions))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
39 $(TR $(TD Normalization) $(TD
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
40 $(LREF absolutePath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
41 $(LREF asAbsolutePath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
42 $(LREF asNormalizedPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
43 $(LREF asRelativePath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
44 $(LREF buildNormalizedPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
45 $(LREF buildPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
46 $(LREF chainPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
47 $(LREF expandTilde)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
48 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
49 $(TR $(TD Partitioning) $(TD
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
50 $(LREF baseName)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
51 $(LREF dirName)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
52 $(LREF dirSeparator)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
53 $(LREF driveName)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
54 $(LREF pathSeparator)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
55 $(LREF pathSplitter)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
56 $(LREF relativePath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
57 $(LREF rootName)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
58 $(LREF stripDrive)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
59 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
60 $(TR $(TD Validation) $(TD
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
61 $(LREF isAbsolute)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
62 $(LREF isDirSeparator)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
63 $(LREF isRooted)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
64 $(LREF isValidFilename)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
65 $(LREF isValidPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
66 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
67 $(TR $(TD Extension) $(TD
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
68 $(LREF defaultExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
69 $(LREF extension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
70 $(LREF setExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
71 $(LREF stripExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
72 $(LREF withDefaultExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
73 $(LREF withExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
74 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
75 $(TR $(TD Other) $(TD
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
76 $(LREF filenameCharCmp)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
77 $(LREF filenameCmp)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
78 $(LREF globMatch)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
79 $(LREF CaseSensitive)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
80 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
81 ))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
82
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
83 Authors:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
84 Lars Tandle Kyllingstad,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
85 $(HTTP digitalmars.com, Walter Bright),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
86 Grzegorz Adam Hankiewicz,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
87 Thomas K$(UUML)hne,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
88 $(HTTP erdani.org, Andrei Alexandrescu)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
89 Copyright:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
90 Copyright (c) 2000-2014, the authors. All rights reserved.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
91 License:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
92 $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
93 Source:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
94 $(PHOBOSSRC std/_path.d)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
95 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
96 module std.path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
97
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
98
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
99 // FIXME
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
100 import std.file; //: getcwd;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
101 static import std.meta;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
102 import std.range.primitives;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
103 import std.traits;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
104
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
105 version (unittest)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
106 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
107 private:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
108 struct TestAliasedString
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
109 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
110 string get() @safe @nogc pure nothrow { return _s; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
111 alias get this;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
112 @disable this(this);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
113 string _s;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
114 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
115
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
116 bool testAliasedString(alias func, Args...)(string s, Args args)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
117 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
118 return func(TestAliasedString(s), args) == func(s, args);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
119 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
120 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
121
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
122 /** String used to separate directory names in a path. Under
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
123 POSIX this is a slash, under Windows a backslash.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
124 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
125 version (Posix) enum string dirSeparator = "/";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
126 else version (Windows) enum string dirSeparator = "\\";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
127 else static assert(0, "unsupported platform");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
128
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
129
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
130
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
131
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
132 /** Path separator string. A colon under POSIX, a semicolon
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
133 under Windows.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
134 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
135 version (Posix) enum string pathSeparator = ":";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
136 else version (Windows) enum string pathSeparator = ";";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
137 else static assert(0, "unsupported platform");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
138
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
139
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
140
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
141
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
142 /** Determines whether the given character is a directory separator.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
143
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
144 On Windows, this includes both $(D `\`) and $(D `/`).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
145 On POSIX, it's just $(D `/`).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
146 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
147 bool isDirSeparator(dchar c) @safe pure nothrow @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
148 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
149 if (c == '/') return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
150 version (Windows) if (c == '\\') return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
151 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
152 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
153
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
154
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
155 /* Determines whether the given character is a drive separator.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
156
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
157 On Windows, this is true if c is the ':' character that separates
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
158 the drive letter from the rest of the path. On POSIX, this always
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
159 returns false.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
160 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
161 private bool isDriveSeparator(dchar c) @safe pure nothrow @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
162 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
163 version (Windows) return c == ':';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
164 else return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
165 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
166
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
167
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
168 /* Combines the isDirSeparator and isDriveSeparator tests. */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
169 version (Windows) private bool isSeparator(dchar c) @safe pure nothrow @nogc
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
170 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
171 return isDirSeparator(c) || isDriveSeparator(c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
172 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
173 version (Posix) private alias isSeparator = isDirSeparator;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
174
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
175
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
176 /* Helper function that determines the position of the last
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
177 drive/directory separator in a string. Returns -1 if none
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
178 is found.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
179 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
180 private ptrdiff_t lastSeparator(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
181 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
182 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
183 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
184 auto i = (cast(ptrdiff_t) path.length) - 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
185 while (i >= 0 && !isSeparator(path[i])) --i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
186 return i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
187 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
188
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
189
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
190 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
191 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
192 private bool isUNC(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
193 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
194 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
195 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
196 return path.length >= 3 && isDirSeparator(path[0]) && isDirSeparator(path[1])
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
197 && !isDirSeparator(path[2]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
198 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
199
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
200 private ptrdiff_t uncRootLength(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
201 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
202 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
203 in { assert(isUNC(path)); }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
204 body
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
205 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
206 ptrdiff_t i = 3;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
207 while (i < path.length && !isDirSeparator(path[i])) ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
208 if (i < path.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
209 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
210 auto j = i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
211 do { ++j; } while (j < path.length && isDirSeparator(path[j]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
212 if (j < path.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
213 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
214 do { ++j; } while (j < path.length && !isDirSeparator(path[j]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
215 i = j;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
216 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
217 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
218 return i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
219 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
220
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
221 private bool hasDrive(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
222 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
223 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
224 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
225 return path.length >= 2 && isDriveSeparator(path[1]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
226 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
227
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
228 private bool isDriveRoot(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
229 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
230 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
231 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
232 return path.length >= 3 && isDriveSeparator(path[1])
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
233 && isDirSeparator(path[2]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
234 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
235 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
236
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
237
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
238 /* Helper functions that strip leading/trailing slashes and backslashes
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
239 from a path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
240 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
241 private auto ltrimDirSeparators(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
242 if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
243 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
244 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
245 static if (isRandomAccessRange!R && hasSlicing!R || isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
246 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
247 int i = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
248 while (i < path.length && isDirSeparator(path[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
249 ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
250 return path[i .. path.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
251 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
252 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
253 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
254 while (!path.empty && isDirSeparator(path.front))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
255 path.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
256 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
257 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
258 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
259
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
260 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
261 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
262 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
263 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
264
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
265 assert(ltrimDirSeparators("//abc//").array == "abc//");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
266 assert(ltrimDirSeparators("//abc//"d).array == "abc//"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
267 assert(ltrimDirSeparators("//abc//".byDchar).array == "abc//"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
268 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
269
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
270 private auto rtrimDirSeparators(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
271 if (isBidirectionalRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
272 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
273 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
274 static if (isRandomAccessRange!R && hasSlicing!R && hasLength!R || isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
275 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
276 auto i = (cast(ptrdiff_t) path.length) - 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
277 while (i >= 0 && isDirSeparator(path[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
278 --i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
279 return path[0 .. i+1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
280 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
281 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
282 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
283 while (!path.empty && isDirSeparator(path.back))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
284 path.popBack();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
285 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
286 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
287 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
288
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
289 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
290 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
291 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
292 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
293
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
294 assert(rtrimDirSeparators("//abc//").array == "//abc");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
295 assert(rtrimDirSeparators("//abc//"d).array == "//abc"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
296
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
297 assert(rtrimDirSeparators(MockBiRange!char("//abc//")).array == "//abc");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
298 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
299
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
300 private auto trimDirSeparators(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
301 if (isBidirectionalRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
302 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
303 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
304 return ltrimDirSeparators(rtrimDirSeparators(path));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
305 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
306
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
307 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
308 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
309 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
310 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
311
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
312 assert(trimDirSeparators("//abc//").array == "abc");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
313 assert(trimDirSeparators("//abc//"d).array == "abc"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
314
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
315 assert(trimDirSeparators(MockBiRange!char("//abc//")).array == "abc");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
316 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
317
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
318
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
319
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
320
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
321 /** This $(D enum) is used as a template argument to functions which
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
322 compare file names, and determines whether the comparison is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
323 case sensitive or not.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
324 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
325 enum CaseSensitive : bool
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
326 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
327 /// File names are case insensitive
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
328 no = false,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
329
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
330 /// File names are case sensitive
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
331 yes = true,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
332
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
333 /** The default (or most common) setting for the current platform.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
334 That is, $(D no) on Windows and Mac OS X, and $(D yes) on all
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
335 POSIX systems except OS X (Linux, *BSD, etc.).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
336 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
337 osDefault = osDefaultCaseSensitivity
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
338 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
339 version (Windows) private enum osDefaultCaseSensitivity = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
340 else version (OSX) private enum osDefaultCaseSensitivity = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
341 else version (Posix) private enum osDefaultCaseSensitivity = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
342 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
343
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
344
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
345
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
346
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
347 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
348 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
349 cs = Whether or not suffix matching is case-sensitive.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
350 path = A path name. It can be a string, or any random-access range of
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
351 characters.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
352 suffix = An optional suffix to be removed from the file name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
353 Returns: The name of the file in the path name, without any leading
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
354 directory and with an optional suffix chopped off.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
355
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
356 If $(D suffix) is specified, it will be compared to $(D path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
357 using $(D filenameCmp!cs),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
358 where $(D cs) is an optional template parameter determining whether
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
359 the comparison is case sensitive or not. See the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
360 $(LREF filenameCmp) documentation for details.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
361
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
362 Example:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
363 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
364 assert(baseName("dir/file.ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
365 assert(baseName("dir/file.ext", ".ext") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
366 assert(baseName("dir/file.ext", ".xyz") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
367 assert(baseName("dir/filename", "name") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
368 assert(baseName("dir/subdir/") == "subdir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
369
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
370 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
371 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
372 assert(baseName(`d:file.ext`) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
373 assert(baseName(`d:\dir\file.ext`) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
374 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
375 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
376
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
377 Note:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
378 This function $(I only) strips away the specified suffix, which
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
379 doesn't necessarily have to represent an extension.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
380 To remove the extension from a path, regardless of what the extension
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
381 is, use $(LREF stripExtension).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
382 To obtain the filename without leading directories and without
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
383 an extension, combine the functions like this:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
384 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
385 assert(baseName(stripExtension("dir/file.ext")) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
386 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
387
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
388 Standards:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
389 This function complies with
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
390 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
391 the POSIX requirements for the 'basename' shell utility)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
392 (with suitable adaptations for Windows paths).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
393 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
394 auto baseName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
395 if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) && !isSomeString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
396 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
397 return _baseName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
398 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
399
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
400 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
401 auto baseName(C)(C[] path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
402 if (isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
403 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
404 return _baseName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
405 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
406
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
407 private R _baseName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
408 if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
409 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
410 auto p1 = stripDrive(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
411 if (p1.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
412 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
413 version (Windows) if (isUNC(path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
414 return path[0 .. 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
415 static if (isSomeString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
416 return null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
417 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
418 return p1; // which is empty
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
419 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
420
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
421 auto p2 = rtrimDirSeparators(p1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
422 if (p2.empty) return p1[0 .. 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
423
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
424 return p2[lastSeparator(p2)+1 .. p2.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
425 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
426
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
427 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
428 inout(C)[] baseName(CaseSensitive cs = CaseSensitive.osDefault, C, C1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
429 (inout(C)[] path, in C1[] suffix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
430 @safe pure //TODO: nothrow (because of filenameCmp())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
431 if (isSomeChar!C && isSomeChar!C1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
432 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
433 auto p = baseName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
434 if (p.length > suffix.length
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
435 && filenameCmp!cs(cast(const(C)[])p[$-suffix.length .. $], suffix) == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
436 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
437 return p[0 .. $-suffix.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
438 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
439 else return p;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
440 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
441
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
442 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
443 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
444 assert(baseName("").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
445 assert(baseName("file.ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
446 assert(baseName("file.ext"d, ".ext") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
447 assert(baseName("file", "file"w.dup) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
448 assert(baseName("dir/file.ext"d.dup) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
449 assert(baseName("dir/file.ext", ".ext"d) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
450 assert(baseName("dir/file"w, "file"d) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
451 assert(baseName("dir///subdir////") == "subdir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
452 assert(baseName("dir/subdir.ext/", ".ext") == "subdir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
453 assert(baseName("dir/subdir/".dup, "subdir") == "subdir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
454 assert(baseName("/"w.dup) == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
455 assert(baseName("//"d.dup) == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
456 assert(baseName("///") == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
457
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
458 assert(baseName!(CaseSensitive.yes)("file.ext", ".EXT") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
459 assert(baseName!(CaseSensitive.no)("file.ext", ".EXT") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
460
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
461 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
462 auto r = MockRange!(immutable(char))(`dir/file.ext`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
463 auto s = r.baseName();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
464 foreach (i, c; `file`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
465 assert(s[i] == c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
466 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
467
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
468 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
469 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
470 assert(baseName(`dir\file.ext`) == `file.ext`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
471 assert(baseName(`dir\file.ext`, `.ext`) == `file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
472 assert(baseName(`dir\file`, `file`) == `file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
473 assert(baseName(`d:file.ext`) == `file.ext`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
474 assert(baseName(`d:file.ext`, `.ext`) == `file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
475 assert(baseName(`d:file`, `file`) == `file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
476 assert(baseName(`dir\\subdir\\\`) == `subdir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
477 assert(baseName(`dir\subdir.ext\`, `.ext`) == `subdir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
478 assert(baseName(`dir\subdir\`, `subdir`) == `subdir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
479 assert(baseName(`\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
480 assert(baseName(`\\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
481 assert(baseName(`\\\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
482 assert(baseName(`d:\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
483 assert(baseName(`d:`).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
484 assert(baseName(`\\server\share\file`) == `file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
485 assert(baseName(`\\server\share\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
486 assert(baseName(`\\server\share`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
487
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
488 auto r = MockRange!(immutable(char))(`\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
489 auto s = r.baseName();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
490 foreach (i, c; `\`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
491 assert(s[i] == c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
492 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
493
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
494 assert(baseName(stripExtension("dir/file.ext")) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
495
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
496 static assert(baseName("dir/file.ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
497 static assert(baseName("dir/file.ext", ".ext") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
498
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
499 static struct DirEntry { string s; alias s this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
500 assert(baseName(DirEntry("dir/file.ext")) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
501 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
502
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
503 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
504 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
505 assert(testAliasedString!baseName("file"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
506
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
507 enum S : string { a = "file/path/to/test" }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
508 assert(S.a.baseName == "test");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
509
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
510 char[S.a.length] sa = S.a[];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
511 assert(sa.baseName == "test");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
512 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
513
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
514 /** Returns the directory part of a path. On Windows, this
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
515 includes the drive letter if present.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
516
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
517 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
518 path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
519
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
520 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
521 A slice of $(D path) or ".".
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
522
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
523 Standards:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
524 This function complies with
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
525 $(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
526 the POSIX requirements for the 'dirname' shell utility)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
527 (with suitable adaptations for Windows paths).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
528 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
529 auto dirName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
530 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) && !isSomeString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
531 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
532 return _dirName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
533 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
534
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
535 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
536 auto dirName(C)(C[] path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
537 if (isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
538 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
539 return _dirName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
540 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
541
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
542 private auto _dirName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
543 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
544 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
545 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
546 static auto result(bool dot, typeof(path[0 .. 1]) p)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
547 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
548 static if (isSomeString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
549 return dot ? "." : p;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
550 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
551 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
552 import std.range : choose, only;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
553 return choose(dot, only(cast(ElementEncodingType!R)'.'), p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
554 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
555 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
556
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
557 if (path.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
558 return result(true, path[0 .. 0]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
559
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
560 auto p = rtrimDirSeparators(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
561 if (p.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
562 return result(false, path[0 .. 1]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
563
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
564 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
565 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
566 if (isUNC(p) && uncRootLength(p) == p.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
567 return result(false, p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
568
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
569 if (p.length == 2 && isDriveSeparator(p[1]) && path.length > 2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
570 return result(false, path[0 .. 3]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
571 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
572
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
573 auto i = lastSeparator(p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
574 if (i == -1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
575 return result(true, p);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
576 if (i == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
577 return result(false, p[0 .. 1]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
578
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
579 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
580 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
581 // If the directory part is either d: or d:\
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
582 // do not chop off the last symbol.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
583 if (isDriveSeparator(p[i]) || isDriveSeparator(p[i-1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
584 return result(false, p[0 .. i+1]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
585 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
586 // Remove any remaining trailing (back)slashes.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
587 return result(false, rtrimDirSeparators(p[0 .. i]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
588 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
589
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
590 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
591 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
592 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
593 assert(dirName("") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
594 assert(dirName("file"w) == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
595 assert(dirName("dir/"d) == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
596 assert(dirName("dir///") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
597 assert(dirName("dir/file"w.dup) == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
598 assert(dirName("dir///file"d.dup) == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
599 assert(dirName("dir/subdir/") == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
600 assert(dirName("/dir/file"w) == "/dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
601 assert(dirName("/file"d) == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
602 assert(dirName("/") == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
603 assert(dirName("///") == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
604
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
605 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
606 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
607 assert(dirName(`dir\`) == `.`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
608 assert(dirName(`dir\\\`) == `.`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
609 assert(dirName(`dir\file`) == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
610 assert(dirName(`dir\\\file`) == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
611 assert(dirName(`dir\subdir\`) == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
612 assert(dirName(`\dir\file`) == `\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
613 assert(dirName(`\file`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
614 assert(dirName(`\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
615 assert(dirName(`\\\`) == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
616 assert(dirName(`d:`) == `d:`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
617 assert(dirName(`d:file`) == `d:`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
618 assert(dirName(`d:\`) == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
619 assert(dirName(`d:\file`) == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
620 assert(dirName(`d:\dir\file`) == `d:\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
621 assert(dirName(`\\server\share\dir\file`) == `\\server\share\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
622 assert(dirName(`\\server\share\file`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
623 assert(dirName(`\\server\share\`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
624 assert(dirName(`\\server\share`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
625 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
626 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
627
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
628 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
629 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
630 assert(testAliasedString!dirName("file"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
631
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
632 enum S : string { a = "file/path/to/test" }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
633 assert(S.a.dirName == "file/path/to");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
634
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
635 char[S.a.length] sa = S.a[];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
636 assert(sa.dirName == "file/path/to");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
637 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
638
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
639 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
640 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
641 static assert(dirName("dir/file") == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
642
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
643 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
644 import std.utf : byChar, byWchar, byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
645
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
646 assert(dirName("".byChar).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
647 assert(dirName("file"w.byWchar).array == "."w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
648 assert(dirName("dir/"d.byDchar).array == "."d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
649 assert(dirName("dir///".byChar).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
650 assert(dirName("dir/subdir/".byChar).array == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
651 assert(dirName("/dir/file"w.byWchar).array == "/dir"w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
652 assert(dirName("/file"d.byDchar).array == "/"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
653 assert(dirName("/".byChar).array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
654 assert(dirName("///".byChar).array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
655
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
656 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
657 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
658 assert(dirName(`dir\`.byChar).array == `.`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
659 assert(dirName(`dir\\\`.byChar).array == `.`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
660 assert(dirName(`dir\file`.byChar).array == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
661 assert(dirName(`dir\\\file`.byChar).array == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
662 assert(dirName(`dir\subdir\`.byChar).array == `dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
663 assert(dirName(`\dir\file`.byChar).array == `\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
664 assert(dirName(`\file`.byChar).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
665 assert(dirName(`\`.byChar).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
666 assert(dirName(`\\\`.byChar).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
667 assert(dirName(`d:`.byChar).array == `d:`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
668 assert(dirName(`d:file`.byChar).array == `d:`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
669 assert(dirName(`d:\`.byChar).array == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
670 assert(dirName(`d:\file`.byChar).array == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
671 assert(dirName(`d:\dir\file`.byChar).array == `d:\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
672 assert(dirName(`\\server\share\dir\file`.byChar).array == `\\server\share\dir`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
673 assert(dirName(`\\server\share\file`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
674 assert(dirName(`\\server\share\`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
675 assert(dirName(`\\server\share`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
676 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
677
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
678 //static assert(dirName("dir/file".byChar).array == "dir");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
679 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
680
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
681
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
682
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
683
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
684 /** Returns the root directory of the specified path, or $(D null) if the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
685 path is not rooted.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
686
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
687 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
688 path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
689
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
690 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
691 A slice of $(D path).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
692 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
693 auto rootName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
694 if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
695 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
696 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
697 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
698 if (path.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
699 goto Lnull;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
700
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
701 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
702 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
703 if (isDirSeparator(path[0])) return path[0 .. 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
704 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
705 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
706 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
707 if (isDirSeparator(path[0]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
708 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
709 if (isUNC(path)) return path[0 .. uncRootLength(path)];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
710 else return path[0 .. 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
711 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
712 else if (path.length >= 3 && isDriveSeparator(path[1]) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
713 isDirSeparator(path[2]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
714 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
715 return path[0 .. 3];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
716 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
717 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
718 else static assert(0, "unsupported platform");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
719
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
720 assert(!isRooted(path));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
721 Lnull:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
722 static if (is(StringTypeOf!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
723 return null; // legacy code may rely on null return rather than slice
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
724 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
725 return path[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
726 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
727
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
728 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
729 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
730 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
731 assert(rootName("") is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
732 assert(rootName("foo") is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
733 assert(rootName("/") == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
734 assert(rootName("/foo/bar") == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
735
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
736 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
737 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
738 assert(rootName("d:foo") is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
739 assert(rootName(`d:\foo`) == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
740 assert(rootName(`\\server\share\foo`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
741 assert(rootName(`\\server\share`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
742 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
743 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
744
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
745 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
746 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
747 assert(testAliasedString!rootName("/foo/bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
748 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
749
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
750 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
751 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
752 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
753 import std.utf : byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
754
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
755 assert(rootName("".byChar).array == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
756 assert(rootName("foo".byChar).array == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
757 assert(rootName("/".byChar).array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
758 assert(rootName("/foo/bar".byChar).array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
759
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
760 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
761 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
762 assert(rootName("d:foo".byChar).array == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
763 assert(rootName(`d:\foo`.byChar).array == `d:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
764 assert(rootName(`\\server\share\foo`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
765 assert(rootName(`\\server\share`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
766 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
767 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
768
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
769 auto rootName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
770 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
771 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
772 return rootName!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
773 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
774
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
775
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
776 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
777 Get the drive portion of a path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
778
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
779 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
780 path = string or range of characters
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
781
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
782 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
783 A slice of $(D _path) that is the drive, or an empty range if the drive
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
784 is not specified. In the case of UNC paths, the network share
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
785 is returned.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
786
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
787 Always returns an empty range on POSIX.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
788 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
789 auto driveName(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
790 if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
791 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
792 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
793 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
794 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
795 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
796 if (hasDrive(path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
797 return path[0 .. 2];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
798 else if (isUNC(path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
799 return path[0 .. uncRootLength(path)];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
800 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
801 static if (isSomeString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
802 return cast(ElementEncodingType!R[]) null; // legacy code may rely on null return rather than slice
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
803 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
804 return path[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
805 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
806
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
807 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
808 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
809 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
810 import std.range : empty;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
811 version (Posix) assert(driveName("c:/foo").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
812 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
813 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
814 assert(driveName(`dir\file`).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
815 assert(driveName(`d:file`) == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
816 assert(driveName(`d:\file`) == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
817 assert(driveName("d:") == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
818 assert(driveName(`\\server\share\file`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
819 assert(driveName(`\\server\share\`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
820 assert(driveName(`\\server\share`) == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
821
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
822 static assert(driveName(`d:\file`) == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
823 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
824 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
825
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
826 auto driveName(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
827 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
828 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
829 return driveName!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
830 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
831
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
832 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
833 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
834 assert(testAliasedString!driveName(`d:\file`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
835 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
836
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
837 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
838 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
839 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
840 import std.utf : byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
841
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
842 version (Posix) assert(driveName("c:/foo".byChar).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
843 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
844 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
845 assert(driveName(`dir\file`.byChar).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
846 assert(driveName(`d:file`.byChar).array == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
847 assert(driveName(`d:\file`.byChar).array == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
848 assert(driveName("d:".byChar).array == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
849 assert(driveName(`\\server\share\file`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
850 assert(driveName(`\\server\share\`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
851 assert(driveName(`\\server\share`.byChar).array == `\\server\share`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
852
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
853 static assert(driveName(`d:\file`).array == "d:");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
854 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
855 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
856
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
857
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
858 /** Strips the drive from a Windows path. On POSIX, the path is returned
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
859 unaltered.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
860
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
861 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
862 path = A pathname
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
863
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
864 Returns: A slice of path without the drive component.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
865 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
866 auto stripDrive(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
867 if ((isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
868 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
869 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
870 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
871 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
872 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
873 if (hasDrive!(BaseOf!R)(path)) return path[2 .. path.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
874 else if (isUNC!(BaseOf!R)(path)) return path[uncRootLength!(BaseOf!R)(path) .. path.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
875 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
876 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
877 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
878
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
879 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
880 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
881 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
882 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
883 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
884 assert(stripDrive(`d:\dir\file`) == `\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
885 assert(stripDrive(`\\server\share\dir\file`) == `\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
886 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
887 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
888
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
889 auto stripDrive(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
890 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
891 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
892 return stripDrive!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
893 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
894
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
895 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
896 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
897 assert(testAliasedString!stripDrive(`d:\dir\file`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
898 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
899
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
900 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
901 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
902 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
903 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
904 assert(stripDrive(`d:\dir\file`) == `\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
905 assert(stripDrive(`\\server\share\dir\file`) == `\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
906 static assert(stripDrive(`d:\dir\file`) == `\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
907
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
908 auto r = MockRange!(immutable(char))(`d:\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
909 auto s = r.stripDrive();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
910 foreach (i, c; `\dir\file`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
911 assert(s[i] == c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
912 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
913 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
914 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
915 assert(stripDrive(`d:\dir\file`) == `d:\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
916
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
917 auto r = MockRange!(immutable(char))(`d:\dir\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
918 auto s = r.stripDrive();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
919 foreach (i, c; `d:\dir\file`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
920 assert(s[i] == c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
921 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
922 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
923
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
924
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
925 /* Helper function that returns the position of the filename/extension
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
926 separator dot in path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
927
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
928 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
929 path = file spec as string or indexable range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
930 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
931 index of extension separator (the dot), or -1 if not found
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
932 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
933 private ptrdiff_t extSeparatorPos(R)(const R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
934 if (isRandomAccessRange!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
935 isNarrowString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
936 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
937 for (auto i = path.length; i-- > 0 && !isSeparator(path[i]); )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
938 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
939 if (path[i] == '.' && i > 0 && !isSeparator(path[i-1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
940 return i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
941 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
942 return -1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
943 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
944
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
945 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
946 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
947 assert(extSeparatorPos("file") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
948 assert(extSeparatorPos("file.ext"w) == 4);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
949 assert(extSeparatorPos("file.ext1.ext2"d) == 9);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
950 assert(extSeparatorPos(".foo".dup) == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
951 assert(extSeparatorPos(".foo.ext"w.dup) == 4);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
952 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
953
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
954 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
955 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
956 assert(extSeparatorPos("dir/file"d.dup) == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
957 assert(extSeparatorPos("dir/file.ext") == 8);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
958 assert(extSeparatorPos("dir/file.ext1.ext2"w) == 13);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
959 assert(extSeparatorPos("dir/.foo"d) == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
960 assert(extSeparatorPos("dir/.foo.ext".dup) == 8);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
961
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
962 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
963 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
964 assert(extSeparatorPos("dir\\file") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
965 assert(extSeparatorPos("dir\\file.ext") == 8);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
966 assert(extSeparatorPos("dir\\file.ext1.ext2") == 13);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
967 assert(extSeparatorPos("dir\\.foo") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
968 assert(extSeparatorPos("dir\\.foo.ext") == 8);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
969
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
970 assert(extSeparatorPos("d:file") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
971 assert(extSeparatorPos("d:file.ext") == 6);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
972 assert(extSeparatorPos("d:file.ext1.ext2") == 11);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
973 assert(extSeparatorPos("d:.foo") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
974 assert(extSeparatorPos("d:.foo.ext") == 6);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
975 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
976
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
977 static assert(extSeparatorPos("file") == -1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
978 static assert(extSeparatorPos("file.ext"w) == 4);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
979 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
980
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
981
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
982 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
983 Params: path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
984 Returns: The _extension part of a file name, including the dot.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
985
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
986 If there is no _extension, $(D null) is returned.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
987 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
988 auto extension(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
989 if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
990 is(StringTypeOf!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
991 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
992 auto i = extSeparatorPos!(BaseOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
993 if (i == -1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
994 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
995 static if (is(StringTypeOf!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
996 return StringTypeOf!R.init[]; // which is null
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
997 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
998 return path[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
999 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1000 else return path[i .. path.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1001 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1002
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1003 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1004 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1005 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1006 import std.range : empty;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1007 assert(extension("file").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1008 assert(extension("file.") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1009 assert(extension("file.ext"w) == ".ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1010 assert(extension("file.ext1.ext2"d) == ".ext2");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1011 assert(extension(".foo".dup).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1012 assert(extension(".foo.ext"w.dup) == ".ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1013
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1014 static assert(extension("file").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1015 static assert(extension("file.ext") == ".ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1016 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1017
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1018 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1019 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1020 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1021 auto r = MockRange!(immutable(char))(`file.ext1.ext2`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1022 auto s = r.extension();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1023 foreach (i, c; `.ext2`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1024 assert(s[i] == c);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1025 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1026
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1027 static struct DirEntry { string s; alias s this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1028 assert(extension(DirEntry("file")).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1029 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1030
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1031
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1032 /** Remove extension from path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1033
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1034 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1035 path = string or range to be sliced
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1036
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1037 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1038 slice of path with the extension (if any) stripped off
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1039 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1040 auto stripExtension(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1041 if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1042 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1043 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1044 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1045 auto i = extSeparatorPos(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1046 return (i == -1) ? path : path[0 .. i];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1047 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1048
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1049 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1050 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1051 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1052 assert(stripExtension("file") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1053 assert(stripExtension("file.ext") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1054 assert(stripExtension("file.ext1.ext2") == "file.ext1");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1055 assert(stripExtension("file.") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1056 assert(stripExtension(".file") == ".file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1057 assert(stripExtension(".file.ext") == ".file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1058 assert(stripExtension("dir/file.ext") == "dir/file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1059 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1060
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1061 auto stripExtension(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1062 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1063 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1064 return stripExtension!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1065 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1066
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1067 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1068 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1069 assert(testAliasedString!stripExtension("file"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1070 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1071
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1072 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1073 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1074 assert(stripExtension("file.ext"w) == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1075 assert(stripExtension("file.ext1.ext2"d) == "file.ext1");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1076
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1077 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1078 import std.utf : byChar, byWchar, byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1079
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1080 assert(stripExtension("file".byChar).array == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1081 assert(stripExtension("file.ext"w.byWchar).array == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1082 assert(stripExtension("file.ext1.ext2"d.byDchar).array == "file.ext1");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1083 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1084
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1085
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1086 /** Sets or replaces an extension.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1087
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1088 If the filename already has an extension, it is replaced. If not, the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1089 extension is simply appended to the filename. Including a leading dot
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1090 in $(D ext) is optional.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1091
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1092 If the extension is empty, this function is equivalent to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1093 $(LREF stripExtension).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1094
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1095 This function normally allocates a new string (the possible exception
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1096 being the case when path is immutable and doesn't already have an
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1097 extension).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1098
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1099 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1100 path = A path name
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1101 ext = The new extension
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1102
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1103 Returns: A string containing the _path given by $(D path), but where
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1104 the extension has been set to $(D ext).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1105
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1106 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1107 $(LREF withExtension) which does not allocate and returns a lazy range.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1108 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1109 immutable(Unqual!C1)[] setExtension(C1, C2)(in C1[] path, in C2[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1110 if (isSomeChar!C1 && !is(C1 == immutable) && is(Unqual!C1 == Unqual!C2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1111 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1112 try
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1113 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1114 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1115 return withExtension(path, ext).to!(typeof(return));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1116 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1117 catch (Exception e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1118 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1119 assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1120 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1121 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1122
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1123 ///ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1124 immutable(C1)[] setExtension(C1, C2)(immutable(C1)[] path, const(C2)[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1125 if (isSomeChar!C1 && is(Unqual!C1 == Unqual!C2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1126 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1127 if (ext.length == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1128 return stripExtension(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1129
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1130 try
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1131 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1132 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1133 return withExtension(path, ext).to!(typeof(return));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1134 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1135 catch (Exception e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1136 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1137 assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1138 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1139 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1140
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1141 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1142 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1143 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1144 assert(setExtension("file", "ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1145 assert(setExtension("file"w, ".ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1146 assert(setExtension("file."d, "ext"d) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1147 assert(setExtension("file.", ".ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1148 assert(setExtension("file.old"w, "new"w) == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1149 assert(setExtension("file.old"d, ".new"d) == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1150 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1151
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1152 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1153 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1154 assert(setExtension("file"w.dup, "ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1155 assert(setExtension("file"w.dup, ".ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1156 assert(setExtension("file."w, "ext"w.dup) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1157 assert(setExtension("file."w, ".ext"w.dup) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1158 assert(setExtension("file.old"d.dup, "new"d) == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1159 assert(setExtension("file.old"d.dup, ".new"d) == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1160
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1161 static assert(setExtension("file", "ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1162 static assert(setExtension("file.old", "new") == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1163
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1164 static assert(setExtension("file"w.dup, "ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1165 static assert(setExtension("file.old"d.dup, "new"d) == "file.new");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1166
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1167 // Issue 10601
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1168 assert(setExtension("file", "") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1169 assert(setExtension("file.ext", "") == "file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1170 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1171
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1172 /************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1173 * Replace existing extension on filespec with new one.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1174 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1175 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1176 * path = string or random access range representing a filespec
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1177 * ext = the new extension
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1178 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1179 * Range with $(D path)'s extension (if any) replaced with $(D ext).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1180 * The element encoding type of the returned range will be the same as $(D path)'s.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1181 * See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1182 * $(LREF setExtension)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1183 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1184 auto withExtension(R, C)(R path, C[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1185 if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1186 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1187 !isConvertibleToString!R &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1188 isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1189 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1190 import std.range : only, chain;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1191 import std.utf : byUTF;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1192
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1193 alias CR = Unqual!(ElementEncodingType!R);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1194 auto dot = only(CR('.'));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1195 if (ext.length == 0 || ext[0] == '.')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1196 dot.popFront(); // so dot is an empty range, too
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1197 return chain(stripExtension(path).byUTF!CR, dot, ext.byUTF!CR);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1198 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1199
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1200 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1201 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1202 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1203 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1204 assert(withExtension("file", "ext").array == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1205 assert(withExtension("file"w, ".ext"w).array == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1206 assert(withExtension("file.ext"w, ".").array == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1207
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1208 import std.utf : byChar, byWchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1209 assert(withExtension("file".byChar, "ext").array == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1210 assert(withExtension("file"w.byWchar, ".ext"w).array == "file.ext"w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1211 assert(withExtension("file.ext"w.byWchar, ".").array == "file."w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1212 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1213
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1214 auto withExtension(R, C)(auto ref R path, C[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1215 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1216 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1217 return withExtension!(StringTypeOf!R)(path, ext);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1218 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1219
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1220 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1221 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1222 assert(testAliasedString!withExtension("file", "ext"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1223 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1224
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1225 /** Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1226 path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1227 ext = The default extension to use.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1228
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1229 Returns: The _path given by $(D path), with the extension given by $(D ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1230 appended if the path doesn't already have one.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1231
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1232 Including the dot in the extension is optional.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1233
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1234 This function always allocates a new string, except in the case when
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1235 path is immutable and already has an extension.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1236 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1237 immutable(Unqual!C1)[] defaultExtension(C1, C2)(in C1[] path, in C2[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1238 if (isSomeChar!C1 && is(Unqual!C1 == Unqual!C2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1239 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1240 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1241 return withDefaultExtension(path, ext).to!(typeof(return));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1242 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1243
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1244 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1245 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1246 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1247 assert(defaultExtension("file", "ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1248 assert(defaultExtension("file", ".ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1249 assert(defaultExtension("file.", "ext") == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1250 assert(defaultExtension("file.old", "new") == "file.old");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1251 assert(defaultExtension("file.old", ".new") == "file.old");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1252 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1253
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1254 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1255 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1256 assert(defaultExtension("file"w.dup, "ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1257 assert(defaultExtension("file.old"d.dup, "new"d) == "file.old");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1258
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1259 static assert(defaultExtension("file", "ext") == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1260 static assert(defaultExtension("file.old", "new") == "file.old");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1261
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1262 static assert(defaultExtension("file"w.dup, "ext"w) == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1263 static assert(defaultExtension("file.old"d.dup, "new"d) == "file.old");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1264 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1265
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1266
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1267 /********************************
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1268 * Set the extension of $(D path) to $(D ext) if $(D path) doesn't have one.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1269 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1270 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1271 * path = filespec as string or range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1272 * ext = extension, may have leading '.'
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1273 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1274 * range with the result
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1275 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1276 auto withDefaultExtension(R, C)(R path, C[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1277 if ((isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1278 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1279 !isConvertibleToString!R &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1280 isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1281 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1282 import std.range : only, chain;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1283 import std.utf : byUTF;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1284
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1285 alias CR = Unqual!(ElementEncodingType!R);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1286 auto dot = only(CR('.'));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1287 auto i = extSeparatorPos(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1288 if (i == -1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1289 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1290 if (ext.length > 0 && ext[0] == '.')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1291 ext = ext[1 .. $]; // remove any leading . from ext[]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1292 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1293 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1294 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1295 // path already has an extension, so make these empty
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1296 ext = ext[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1297 dot.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1298 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1299 return chain(path.byUTF!CR, dot, ext.byUTF!CR);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1300 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1301
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1302 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1303 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1304 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1305 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1306 assert(withDefaultExtension("file", "ext").array == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1307 assert(withDefaultExtension("file"w, ".ext").array == "file.ext"w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1308 assert(withDefaultExtension("file.", "ext").array == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1309 assert(withDefaultExtension("file", "").array == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1310
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1311 import std.utf : byChar, byWchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1312 assert(withDefaultExtension("file".byChar, "ext").array == "file.ext");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1313 assert(withDefaultExtension("file"w.byWchar, ".ext").array == "file.ext"w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1314 assert(withDefaultExtension("file.".byChar, "ext"d).array == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1315 assert(withDefaultExtension("file".byChar, "").array == "file.");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1316 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1317
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1318 auto withDefaultExtension(R, C)(auto ref R path, C[] ext)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1319 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1320 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1321 return withDefaultExtension!(StringTypeOf!R, C)(path, ext);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1322 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1323
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1324 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1325 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1326 assert(testAliasedString!withDefaultExtension("file", "ext"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1327 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1328
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1329 /** Combines one or more path segments.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1330
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1331 This function takes a set of path segments, given as an input
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1332 range of string elements or as a set of string arguments,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1333 and concatenates them with each other. Directory separators
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1334 are inserted between segments if necessary. If any of the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1335 path segments are absolute (as defined by $(LREF isAbsolute)), the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1336 preceding segments will be dropped.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1337
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1338 On Windows, if one of the path segments are rooted, but not absolute
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1339 (e.g. $(D `\foo`)), all preceding path segments down to the previous
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1340 root will be dropped. (See below for an example.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1341
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1342 This function always allocates memory to hold the resulting path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1343 The variadic overload is guaranteed to only perform a single
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1344 allocation, as is the range version if $(D paths) is a forward
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1345 range.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1346
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1347 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1348 segments = An input range of segments to assemble the path from.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1349 Returns: The assembled path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1350 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1351 immutable(ElementEncodingType!(ElementType!Range))[]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1352 buildPath(Range)(Range segments)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1353 if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1354 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1355 if (segments.empty) return null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1356
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1357 // If this is a forward range, we can pre-calculate a maximum length.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1358 static if (isForwardRange!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1359 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1360 auto segments2 = segments.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1361 size_t precalc = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1362 foreach (segment; segments2) precalc += segment.length + 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1363 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1364 // Otherwise, just venture a guess and resize later if necessary.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1365 else size_t precalc = 255;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1366
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1367 auto buf = new Unqual!(ElementEncodingType!(ElementType!Range))[](precalc);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1368 size_t pos = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1369 foreach (segment; segments)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1370 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1371 if (segment.empty) continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1372 static if (!isForwardRange!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1373 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1374 immutable neededLength = pos + segment.length + 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1375 if (buf.length < neededLength)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1376 buf.length = reserve(buf, neededLength + buf.length/2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1377 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1378 auto r = chainPath(buf[0 .. pos], segment);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1379 size_t i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1380 foreach (c; r)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1381 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1382 buf[i] = c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1383 ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1384 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1385 pos = i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1386 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1387 static U trustedCast(U, V)(V v) @trusted pure nothrow { return cast(U) v; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1388 return trustedCast!(typeof(return))(buf[0 .. pos]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1389 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1390
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1391 /// ditto
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1392 immutable(C)[] buildPath(C)(const(C)[][] paths...)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1393 @safe pure nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1394 if (isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1395 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1396 return buildPath!(typeof(paths))(paths);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1397 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1398
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1399 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1400 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1401 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1402 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1403 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1404 assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1405 assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1406 assert(buildPath("/foo", "/bar") == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1407 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1408
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1409 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1410 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1411 assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1412 assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1413 assert(buildPath("foo", `d:\bar`) == `d:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1414 assert(buildPath("foo", `\bar`) == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1415 assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1416 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1417 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1418
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1419 @system unittest // non-documented
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1420 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1421 import std.range;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1422 // ir() wraps an array in a plain (i.e. non-forward) input range, so that
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1423 // we can test both code paths
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1424 InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p); }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1425 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1426 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1427 assert(buildPath("foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1428 assert(buildPath("/foo/") == "/foo/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1429 assert(buildPath("foo", "bar") == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1430 assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1431 assert(buildPath("foo/".dup, "bar") == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1432 assert(buildPath("foo///", "bar".dup) == "foo///bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1433 assert(buildPath("/foo"w, "bar"w) == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1434 assert(buildPath("foo"w.dup, "/bar"w) == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1435 assert(buildPath("foo"w, "bar/"w.dup) == "foo/bar/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1436 assert(buildPath("/"d, "foo"d) == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1437 assert(buildPath(""d.dup, "foo"d) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1438 assert(buildPath("foo"d, ""d.dup) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1439 assert(buildPath("foo", "bar".dup, "baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1440 assert(buildPath("foo"w, "/bar"w, "baz"w.dup) == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1441
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1442 static assert(buildPath("foo", "bar", "baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1443 static assert(buildPath("foo", "/bar", "baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1444
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1445 // The following are mostly duplicates of the above, except that the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1446 // range version does not accept mixed constness.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1447 assert(buildPath(ir("foo")) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1448 assert(buildPath(ir("/foo/")) == "/foo/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1449 assert(buildPath(ir("foo", "bar")) == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1450 assert(buildPath(ir("foo", "bar", "baz")) == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1451 assert(buildPath(ir("foo/".dup, "bar".dup)) == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1452 assert(buildPath(ir("foo///".dup, "bar".dup)) == "foo///bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1453 assert(buildPath(ir("/foo"w, "bar"w)) == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1454 assert(buildPath(ir("foo"w.dup, "/bar"w.dup)) == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1455 assert(buildPath(ir("foo"w.dup, "bar/"w.dup)) == "foo/bar/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1456 assert(buildPath(ir("/"d, "foo"d)) == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1457 assert(buildPath(ir(""d.dup, "foo"d.dup)) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1458 assert(buildPath(ir("foo"d, ""d)) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1459 assert(buildPath(ir("foo", "bar", "baz")) == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1460 assert(buildPath(ir("foo"w.dup, "/bar"w.dup, "baz"w.dup)) == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1461 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1462 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1463 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1464 assert(buildPath("foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1465 assert(buildPath(`\foo/`) == `\foo/`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1466 assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1467 assert(buildPath("foo", `\bar`) == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1468 assert(buildPath(`c:\foo`, "bar") == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1469 assert(buildPath("foo"w, `d:\bar`w.dup) == `d:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1470 assert(buildPath(`c:\foo\bar`, `\baz`) == `c:\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1471 assert(buildPath(`\\foo\bar\baz`d, `foo`d, `\bar`d) == `\\foo\bar\bar`d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1472
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1473 static assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1474 static assert(buildPath("foo", `c:\bar`, "baz") == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1475
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1476 assert(buildPath(ir("foo")) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1477 assert(buildPath(ir(`\foo/`)) == `\foo/`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1478 assert(buildPath(ir("foo", "bar", "baz")) == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1479 assert(buildPath(ir("foo", `\bar`)) == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1480 assert(buildPath(ir(`c:\foo`, "bar")) == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1481 assert(buildPath(ir("foo"w.dup, `d:\bar`w.dup)) == `d:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1482 assert(buildPath(ir(`c:\foo\bar`, `\baz`)) == `c:\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1483 assert(buildPath(ir(`\\foo\bar\baz`d, `foo`d, `\bar`d)) == `\\foo\bar\bar`d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1484 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1485
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1486 // Test that allocation works as it should.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1487 auto manyShort = "aaa".repeat(1000).array();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1488 auto manyShortCombined = join(manyShort, dirSeparator);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1489 assert(buildPath(manyShort) == manyShortCombined);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1490 assert(buildPath(ir(manyShort)) == manyShortCombined);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1491
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1492 auto fewLong = 'b'.repeat(500).array().repeat(10).array();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1493 auto fewLongCombined = join(fewLong, dirSeparator);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1494 assert(buildPath(fewLong) == fewLongCombined);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1495 assert(buildPath(ir(fewLong)) == fewLongCombined);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1496 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1497
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1498 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1499 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1500 // Test for issue 7397
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1501 string[] ary = ["a", "b"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1502 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1503 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1504 assert(buildPath(ary) == "a/b");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1505 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1506 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1507 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1508 assert(buildPath(ary) == `a\b`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1509 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1510 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1511
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1512
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1513 /**
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1514 * Concatenate path segments together to form one path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1515 *
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1516 * Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1517 * r1 = first segment
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1518 * r2 = second segment
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1519 * ranges = 0 or more segments
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1520 * Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1521 * Lazy range which is the concatenation of r1, r2 and ranges with path separators.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1522 * The resulting element type is that of r1.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1523 * See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1524 * $(LREF buildPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1525 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1526 auto chainPath(R1, R2, Ranges...)(R1 r1, R2 r2, Ranges ranges)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1527 if ((isRandomAccessRange!R1 && hasSlicing!R1 && hasLength!R1 && isSomeChar!(ElementType!R1) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1528 isNarrowString!R1 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1529 !isConvertibleToString!R1) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1530 (isRandomAccessRange!R2 && hasSlicing!R2 && hasLength!R2 && isSomeChar!(ElementType!R2) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1531 isNarrowString!R2 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1532 !isConvertibleToString!R2) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1533 (Ranges.length == 0 || is(typeof(chainPath(r2, ranges))))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1534 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1535 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1536 static if (Ranges.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1537 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1538 return chainPath(chainPath(r1, r2), ranges);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1539 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1540 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1541 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1542 import std.range : only, chain;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1543 import std.utf : byUTF;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1544
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1545 alias CR = Unqual!(ElementEncodingType!R1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1546 auto sep = only(CR(dirSeparator[0]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1547 bool usesep = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1548
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1549 auto pos = r1.length;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1550
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1551 if (pos)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1552 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1553 if (isRooted(r2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1554 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1555 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1556 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1557 pos = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1558 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1559 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1560 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1561 if (isAbsolute(r2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1562 pos = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1563 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1564 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1565 pos = rootName(r1).length;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1566 if (pos > 0 && isDirSeparator(r1[pos - 1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1567 --pos;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1568 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1569 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1570 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1571 static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1572 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1573 else if (!isDirSeparator(r1[pos - 1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1574 usesep = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1575 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1576 if (!usesep)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1577 sep.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1578 // Return r1 ~ '/' ~ r2
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1579 return chain(r1[0 .. pos].byUTF!CR, sep, r2.byUTF!CR);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1580 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1581 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1582
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1583 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1584 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1585 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1586 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1587 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1588 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1589 assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1590 assert(chainPath("/foo/", "bar/baz").array == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1591 assert(chainPath("/foo", "/bar").array == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1592 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1593
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1594 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1595 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1596 assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1597 assert(chainPath(`c:\foo`, `bar\baz`).array == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1598 assert(chainPath("foo", `d:\bar`).array == `d:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1599 assert(chainPath("foo", `\bar`).array == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1600 assert(chainPath(`c:\foo`, `\bar`).array == `c:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1601 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1602
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1603 import std.utf : byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1604 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1605 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1606 assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1607 assert(chainPath("/foo/".byChar, "bar/baz").array == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1608 assert(chainPath("/foo", "/bar".byChar).array == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1609 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1610
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1611 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1612 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1613 assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1614 assert(chainPath(`c:\foo`.byChar, `bar\baz`).array == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1615 assert(chainPath("foo", `d:\bar`).array == `d:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1616 assert(chainPath("foo", `\bar`.byChar).array == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1617 assert(chainPath(`c:\foo`, `\bar`w).array == `c:\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1618 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1619 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1620
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1621 auto chainPath(Ranges...)(auto ref Ranges ranges)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1622 if (Ranges.length >= 2 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1623 std.meta.anySatisfy!(isConvertibleToString, Ranges))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1624 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1625 import std.meta : staticMap;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1626 alias Types = staticMap!(convertToString, Ranges);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1627 return chainPath!Types(ranges);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1628 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1629
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1630 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1631 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1632 assert(chainPath(TestAliasedString(null), TestAliasedString(null), TestAliasedString(null)).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1633 assert(chainPath(TestAliasedString(null), TestAliasedString(null), "").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1634 assert(chainPath(TestAliasedString(null), "", TestAliasedString(null)).empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1635 static struct S { string s; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1636 static assert(!__traits(compiles, chainPath(TestAliasedString(null), S(""), TestAliasedString(null))));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1637 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1638
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1639 /** Performs the same task as $(LREF buildPath),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1640 while at the same time resolving current/parent directory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1641 symbols ($(D ".") and $(D "..")) and removing superfluous
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1642 directory separators.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1643 It will return "." if the path leads to the starting directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1644 On Windows, slashes are replaced with backslashes.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1645
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1646 Using buildNormalizedPath on null paths will always return null.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1647
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1648 Note that this function does not resolve symbolic links.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1649
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1650 This function always allocates memory to hold the resulting path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1651 Use $(LREF asNormalizedPath) to not allocate memory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1652
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1653 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1654 paths = An array of paths to assemble.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1655
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1656 Returns: The assembled path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1657 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1658 immutable(C)[] buildNormalizedPath(C)(const(C[])[] paths...)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1659 @trusted pure nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1660 if (isSomeChar!C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1661 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1662 import std.array : array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1663
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1664 const(C)[] result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1665 foreach (path; paths)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1666 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1667 if (result)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1668 result = chainPath(result, path).array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1669 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1670 result = path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1671 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1672 result = asNormalizedPath(result).array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1673 return cast(typeof(return)) result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1674 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1675
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1676 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1677 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1678 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1679 assert(buildNormalizedPath("foo", "..") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1680
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1681 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1682 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1683 assert(buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1684 assert(buildNormalizedPath("../foo/.") == "../foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1685 assert(buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1686 assert(buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1687 assert(buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1688 assert(buildNormalizedPath("/foo/./bar", "../../baz") == "/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1689 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1690
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1691 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1692 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1693 assert(buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1694 assert(buildNormalizedPath(`..\foo\.`) == `..\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1695 assert(buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1696 assert(buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1697 assert(buildNormalizedPath(`\\server\share\foo`, `..\bar`) ==
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1698 `\\server\share\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1699 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1700 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1701
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1702 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1703 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1704 assert(buildNormalizedPath(".", ".") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1705 assert(buildNormalizedPath("foo", "..") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1706 assert(buildNormalizedPath("", "") is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1707 assert(buildNormalizedPath("", ".") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1708 assert(buildNormalizedPath(".", "") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1709 assert(buildNormalizedPath(null, "foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1710 assert(buildNormalizedPath("", "foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1711 assert(buildNormalizedPath("", "") == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1712 assert(buildNormalizedPath("", null) == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1713 assert(buildNormalizedPath(null, "") == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1714 assert(buildNormalizedPath!(char)(null, null) == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1715
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1716 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1717 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1718 assert(buildNormalizedPath("/", "foo", "bar") == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1719 assert(buildNormalizedPath("foo", "bar", "baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1720 assert(buildNormalizedPath("foo", "bar/baz") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1721 assert(buildNormalizedPath("foo", "bar//baz///") == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1722 assert(buildNormalizedPath("/foo", "bar/baz") == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1723 assert(buildNormalizedPath("/foo", "/bar/baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1724 assert(buildNormalizedPath("/foo/..", "/bar/./baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1725 assert(buildNormalizedPath("/foo/..", "bar/baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1726 assert(buildNormalizedPath("/foo/../../", "bar/baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1727 assert(buildNormalizedPath("/foo/bar", "../baz") == "/foo/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1728 assert(buildNormalizedPath("/foo/bar", "../../baz") == "/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1729 assert(buildNormalizedPath("/foo/bar", ".././/baz/..", "wee/") == "/foo/wee");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1730 assert(buildNormalizedPath("//foo/bar", "baz///wee") == "/foo/bar/baz/wee");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1731 static assert(buildNormalizedPath("/foo/..", "/bar/./baz") == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1732 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1733 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1734 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1735 assert(buildNormalizedPath(`\`, `foo`, `bar`) == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1736 assert(buildNormalizedPath(`foo`, `bar`, `baz`) == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1737 assert(buildNormalizedPath(`foo`, `bar\baz`) == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1738 assert(buildNormalizedPath(`foo`, `bar\\baz\\\`) == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1739 assert(buildNormalizedPath(`\foo`, `bar\baz`) == `\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1740 assert(buildNormalizedPath(`\foo`, `\bar\baz`) == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1741 assert(buildNormalizedPath(`\foo\..`, `\bar\.\baz`) == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1742 assert(buildNormalizedPath(`\foo\..`, `bar\baz`) == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1743 assert(buildNormalizedPath(`\foo\..\..\`, `bar\baz`) == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1744 assert(buildNormalizedPath(`\foo\bar`, `..\baz`) == `\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1745 assert(buildNormalizedPath(`\foo\bar`, `../../baz`) == `\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1746 assert(buildNormalizedPath(`\foo\bar`, `..\.\/baz\..`, `wee\`) == `\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1747
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1748 assert(buildNormalizedPath(`c:\`, `foo`, `bar`) == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1749 assert(buildNormalizedPath(`c:foo`, `bar`, `baz`) == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1750 assert(buildNormalizedPath(`c:foo`, `bar\baz`) == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1751 assert(buildNormalizedPath(`c:foo`, `bar\\baz\\\`) == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1752 assert(buildNormalizedPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1753 assert(buildNormalizedPath(`c:\foo`, `\bar\baz`) == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1754 assert(buildNormalizedPath(`c:\foo\..`, `\bar\.\baz`) == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1755 assert(buildNormalizedPath(`c:\foo\..`, `bar\baz`) == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1756 assert(buildNormalizedPath(`c:\foo\..\..\`, `bar\baz`) == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1757 assert(buildNormalizedPath(`c:\foo\bar`, `..\baz`) == `c:\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1758 assert(buildNormalizedPath(`c:\foo\bar`, `..\..\baz`) == `c:\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1759 assert(buildNormalizedPath(`c:\foo\bar`, `..\.\\baz\..`, `wee\`) == `c:\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1760
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1761 assert(buildNormalizedPath(`\\server\share`, `foo`, `bar`) == `\\server\share\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1762 assert(buildNormalizedPath(`\\server\share\`, `foo`, `bar`) == `\\server\share\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1763 assert(buildNormalizedPath(`\\server\share\foo`, `bar\baz`) == `\\server\share\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1764 assert(buildNormalizedPath(`\\server\share\foo`, `\bar\baz`) == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1765 assert(buildNormalizedPath(`\\server\share\foo\..`, `\bar\.\baz`) == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1766 assert(buildNormalizedPath(`\\server\share\foo\..`, `bar\baz`) == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1767 assert(buildNormalizedPath(`\\server\share\foo\..\..\`, `bar\baz`) == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1768 assert(buildNormalizedPath(`\\server\share\foo\bar`, `..\baz`) == `\\server\share\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1769 assert(buildNormalizedPath(`\\server\share\foo\bar`, `..\..\baz`) == `\\server\share\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1770 assert(buildNormalizedPath(`\\server\share\foo\bar`, `..\.\\baz\..`, `wee\`) == `\\server\share\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1771
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1772 static assert(buildNormalizedPath(`\foo\..\..\`, `bar\baz`) == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1773 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1774 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1775 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1776
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1777 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1778 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1779 // Test for issue 7397
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1780 string[] ary = ["a", "b"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1781 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1782 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1783 assert(buildNormalizedPath(ary) == "a/b");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1784 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1785 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1786 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1787 assert(buildNormalizedPath(ary) == `a\b`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1788 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1789 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1790
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1791
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1792 /** Normalize a path by resolving current/parent directory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1793 symbols ($(D ".") and $(D "..")) and removing superfluous
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1794 directory separators.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1795 It will return "." if the path leads to the starting directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1796 On Windows, slashes are replaced with backslashes.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1797
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1798 Using asNormalizedPath on empty paths will always return an empty path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1799
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1800 Does not resolve symbolic links.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1801
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1802 This function always allocates memory to hold the resulting path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1803 Use $(LREF buildNormalizedPath) to allocate memory and return a string.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1804
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1805 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1806 path = string or random access range representing the _path to normalize
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1807
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1808 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1809 normalized path as a forward range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1810 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1811
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1812 auto asNormalizedPath(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1813 if (isSomeChar!(ElementEncodingType!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1814 (isRandomAccessRange!R && hasSlicing!R && hasLength!R || isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1815 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1816 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1817 alias C = Unqual!(ElementEncodingType!R);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1818 alias S = typeof(path[0 .. 0]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1819
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1820 static struct Result
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1821 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1822 @property bool empty()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1823 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1824 return c == c.init;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1825 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1826
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1827 @property C front()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1828 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1829 return c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1830 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1831
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1832 void popFront()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1833 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1834 C lastc = c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1835 c = c.init;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1836 if (!element.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1837 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1838 c = getElement0();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1839 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1840 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1841 L1:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1842 while (1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1843 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1844 if (elements.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1845 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1846 element = element[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1847 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1848 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1849 element = elements.front;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1850 elements.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1851 if (isDot(element) || (rooted && isDotDot(element)))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1852 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1853
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1854 if (rooted || !isDotDot(element))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1855 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1856 int n = 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1857 auto elements2 = elements.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1858 while (!elements2.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1859 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1860 auto e = elements2.front;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1861 elements2.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1862 if (isDot(e))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1863 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1864 if (isDotDot(e))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1865 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1866 --n;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1867 if (n == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1868 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1869 elements = elements2;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1870 element = element[0 .. 0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1871 continue L1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1872 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1873 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1874 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1875 ++n;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1876 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1877 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1878 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1879 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1880
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1881 static assert(dirSeparator.length == 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1882 if (lastc == dirSeparator[0] || lastc == lastc.init)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1883 c = getElement0();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1884 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1885 c = dirSeparator[0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1886 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1887
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1888 static if (isForwardRange!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1889 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1890 @property auto save()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1891 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1892 auto result = this;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1893 result.element = element.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1894 result.elements = elements.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1895 return result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1896 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1897 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1898
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1899 private:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1900 this(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1901 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1902 element = rootName(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1903 auto i = element.length;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1904 while (i < path.length && isDirSeparator(path[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1905 ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1906 rooted = i > 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1907 elements = pathSplitter(path[i .. $]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1908 popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1909 if (c == c.init && path.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1910 c = C('.');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1911 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1912
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1913 C getElement0()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1914 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1915 static if (isNarrowString!S) // avoid autodecode
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1916 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1917 C c = element[0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1918 element = element[1 .. $];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1919 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1920 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1921 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1922 C c = element.front;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1923 element.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1924 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1925 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1926 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1927 if (c == '/') // can appear in root element
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1928 c = '\\'; // use native Windows directory separator
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1929 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1930 return c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1931 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1932
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1933 // See if elem is "."
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1934 static bool isDot(S elem)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1935 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1936 return elem.length == 1 && elem[0] == '.';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1937 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1938
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1939 // See if elem is ".."
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1940 static bool isDotDot(S elem)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1941 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1942 return elem.length == 2 && elem[0] == '.' && elem[1] == '.';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1943 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1944
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1945 bool rooted; // the path starts with a root directory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1946 C c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1947 S element;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1948 typeof(pathSplitter(path[0 .. 0])) elements;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1949 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1950
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1951 return Result(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1952 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1953
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1954 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1955 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1956 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1957 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1958 assert(asNormalizedPath("foo/..").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1959
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1960 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1961 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1962 assert(asNormalizedPath("/foo/./bar/..//baz/").array == "/foo/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1963 assert(asNormalizedPath("../foo/.").array == "../foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1964 assert(asNormalizedPath("/foo/bar/baz/").array == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1965 assert(asNormalizedPath("/foo/./bar/../../baz").array == "/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1966 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1967
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1968 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1969 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1970 assert(asNormalizedPath(`c:\foo\.\bar/..\\baz\`).array == `c:\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1971 assert(asNormalizedPath(`..\foo\.`).array == `..\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1972 assert(asNormalizedPath(`c:\foo\bar\baz\`).array == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1973 assert(asNormalizedPath(`c:\foo\bar/..`).array == `c:\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1974 assert(asNormalizedPath(`\\server\share\foo\..\bar`).array ==
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1975 `\\server\share\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1976 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1977 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1978
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1979 auto asNormalizedPath(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1980 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1981 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1982 return asNormalizedPath!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1983 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1984
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1985 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1986 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1987 assert(testAliasedString!asNormalizedPath(null));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1988 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1989
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1990 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1991 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1992 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1993 import std.utf : byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1994
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1995 assert(asNormalizedPath("").array is null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1996 assert(asNormalizedPath("foo").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1997 assert(asNormalizedPath(".").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1998 assert(asNormalizedPath("./.").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
1999 assert(asNormalizedPath("foo/..").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2000
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2001 auto save = asNormalizedPath("fob").save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2002 save.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2003 assert(save.front == 'o');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2004
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2005 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2006 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2007 assert(asNormalizedPath("/foo/bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2008 assert(asNormalizedPath("foo/bar/baz").array == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2009 assert(asNormalizedPath("foo/bar/baz").array == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2010 assert(asNormalizedPath("foo/bar//baz///").array == "foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2011 assert(asNormalizedPath("/foo/bar/baz").array == "/foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2012 assert(asNormalizedPath("/foo/../bar/baz").array == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2013 assert(asNormalizedPath("/foo/../..//bar/baz").array == "/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2014 assert(asNormalizedPath("/foo/bar/../baz").array == "/foo/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2015 assert(asNormalizedPath("/foo/bar/../../baz").array == "/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2016 assert(asNormalizedPath("/foo/bar/.././/baz/../wee/").array == "/foo/wee");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2017 assert(asNormalizedPath("//foo/bar/baz///wee").array == "/foo/bar/baz/wee");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2018
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2019 assert(asNormalizedPath("foo//bar").array == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2020 assert(asNormalizedPath("foo/bar").array == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2021
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2022 //Curent dir path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2023 assert(asNormalizedPath("./").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2024 assert(asNormalizedPath("././").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2025 assert(asNormalizedPath("./foo/..").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2026 assert(asNormalizedPath("foo/..").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2027 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2028 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2029 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2030 assert(asNormalizedPath(`\foo\bar`).array == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2031 assert(asNormalizedPath(`foo\bar\baz`).array == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2032 assert(asNormalizedPath(`foo\bar\baz`).array == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2033 assert(asNormalizedPath(`foo\bar\\baz\\\`).array == `foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2034 assert(asNormalizedPath(`\foo\bar\baz`).array == `\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2035 assert(asNormalizedPath(`\foo\..\\bar\.\baz`).array == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2036 assert(asNormalizedPath(`\foo\..\bar\baz`).array == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2037 assert(asNormalizedPath(`\foo\..\..\\bar\baz`).array == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2038
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2039 assert(asNormalizedPath(`\foo\bar\..\baz`).array == `\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2040 assert(asNormalizedPath(`\foo\bar\../../baz`).array == `\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2041 assert(asNormalizedPath(`\foo\bar\..\.\/baz\..\wee\`).array == `\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2042
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2043 assert(asNormalizedPath(`c:\foo\bar`).array == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2044 assert(asNormalizedPath(`c:foo\bar\baz`).array == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2045 assert(asNormalizedPath(`c:foo\bar\baz`).array == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2046 assert(asNormalizedPath(`c:foo\bar\\baz\\\`).array == `c:foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2047 assert(asNormalizedPath(`c:\foo\bar\baz`).array == `c:\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2048
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2049 assert(asNormalizedPath(`c:\foo\..\\bar\.\baz`).array == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2050 assert(asNormalizedPath(`c:\foo\..\bar\baz`).array == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2051 assert(asNormalizedPath(`c:\foo\..\..\\bar\baz`).array == `c:\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2052 assert(asNormalizedPath(`c:\foo\bar\..\baz`).array == `c:\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2053 assert(asNormalizedPath(`c:\foo\bar\..\..\baz`).array == `c:\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2054 assert(asNormalizedPath(`c:\foo\bar\..\.\\baz\..\wee\`).array == `c:\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2055 assert(asNormalizedPath(`\\server\share\foo\bar`).array == `\\server\share\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2056 assert(asNormalizedPath(`\\server\share\\foo\bar`).array == `\\server\share\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2057 assert(asNormalizedPath(`\\server\share\foo\bar\baz`).array == `\\server\share\foo\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2058 assert(asNormalizedPath(`\\server\share\foo\..\\bar\.\baz`).array == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2059 assert(asNormalizedPath(`\\server\share\foo\..\bar\baz`).array == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2060 assert(asNormalizedPath(`\\server\share\foo\..\..\\bar\baz`).array == `\\server\share\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2061 assert(asNormalizedPath(`\\server\share\foo\bar\..\baz`).array == `\\server\share\foo\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2062 assert(asNormalizedPath(`\\server\share\foo\bar\..\..\baz`).array == `\\server\share\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2063 assert(asNormalizedPath(`\\server\share\foo\bar\..\.\\baz\..\wee\`).array == `\\server\share\foo\wee`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2064
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2065 static assert(asNormalizedPath(`\foo\..\..\\bar\baz`).array == `\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2066
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2067 assert(asNormalizedPath("foo//bar").array == `foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2068
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2069 //Curent dir path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2070 assert(asNormalizedPath(`.\`).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2071 assert(asNormalizedPath(`.\.\`).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2072 assert(asNormalizedPath(`.\foo\..`).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2073 assert(asNormalizedPath(`foo\..`).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2074 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2075 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2076 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2077
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2078 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2079 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2080 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2081
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2082 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2083 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2084 // Trivial
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2085 assert(asNormalizedPath("").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2086 assert(asNormalizedPath("foo/bar").array == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2087
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2088 // Correct handling of leading slashes
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2089 assert(asNormalizedPath("/").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2090 assert(asNormalizedPath("///").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2091 assert(asNormalizedPath("////").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2092 assert(asNormalizedPath("/foo/bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2093 assert(asNormalizedPath("//foo/bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2094 assert(asNormalizedPath("///foo/bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2095 assert(asNormalizedPath("////foo/bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2096
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2097 // Correct handling of single-dot symbol (current directory)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2098 assert(asNormalizedPath("/./foo").array == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2099 assert(asNormalizedPath("/foo/./bar").array == "/foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2100
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2101 assert(asNormalizedPath("./foo").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2102 assert(asNormalizedPath("././foo").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2103 assert(asNormalizedPath("foo/././bar").array == "foo/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2104
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2105 // Correct handling of double-dot symbol (previous directory)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2106 assert(asNormalizedPath("/foo/../bar").array == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2107 assert(asNormalizedPath("/foo/../../bar").array == "/bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2108 assert(asNormalizedPath("/../foo").array == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2109 assert(asNormalizedPath("/../../foo").array == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2110 assert(asNormalizedPath("/foo/..").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2111 assert(asNormalizedPath("/foo/../..").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2112
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2113 assert(asNormalizedPath("foo/../bar").array == "bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2114 assert(asNormalizedPath("foo/../../bar").array == "../bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2115 assert(asNormalizedPath("../foo").array == "../foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2116 assert(asNormalizedPath("../../foo").array == "../../foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2117 assert(asNormalizedPath("../foo/../bar").array == "../bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2118 assert(asNormalizedPath(".././../foo").array == "../../foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2119 assert(asNormalizedPath("foo/bar/..").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2120 assert(asNormalizedPath("/foo/../..").array == "/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2121
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2122 // The ultimate path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2123 assert(asNormalizedPath("/foo/../bar//./../...///baz//").array == "/.../baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2124 static assert(asNormalizedPath("/foo/../bar//./../...///baz//").array == "/.../baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2125 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2126 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2127 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2128 // Trivial
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2129 assert(asNormalizedPath("").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2130 assert(asNormalizedPath(`foo\bar`).array == `foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2131 assert(asNormalizedPath("foo/bar").array == `foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2132
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2133 // Correct handling of absolute paths
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2134 assert(asNormalizedPath("/").array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2135 assert(asNormalizedPath(`\`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2136 assert(asNormalizedPath(`\\\`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2137 assert(asNormalizedPath(`\\\\`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2138 assert(asNormalizedPath(`\foo\bar`).array == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2139 assert(asNormalizedPath(`\\foo`).array == `\\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2140 assert(asNormalizedPath(`\\foo\\`).array == `\\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2141 assert(asNormalizedPath(`\\foo/bar`).array == `\\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2142 assert(asNormalizedPath(`\\\foo\bar`).array == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2143 assert(asNormalizedPath(`\\\\foo\bar`).array == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2144 assert(asNormalizedPath(`c:\`).array == `c:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2145 assert(asNormalizedPath(`c:\foo\bar`).array == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2146 assert(asNormalizedPath(`c:\\foo\bar`).array == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2147
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2148 // Correct handling of single-dot symbol (current directory)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2149 assert(asNormalizedPath(`\./foo`).array == `\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2150 assert(asNormalizedPath(`\foo/.\bar`).array == `\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2151
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2152 assert(asNormalizedPath(`.\foo`).array == `foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2153 assert(asNormalizedPath(`./.\foo`).array == `foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2154 assert(asNormalizedPath(`foo\.\./bar`).array == `foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2155
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2156 // Correct handling of double-dot symbol (previous directory)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2157 assert(asNormalizedPath(`\foo\..\bar`).array == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2158 assert(asNormalizedPath(`\foo\../..\bar`).array == `\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2159 assert(asNormalizedPath(`\..\foo`).array == `\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2160 assert(asNormalizedPath(`\..\..\foo`).array == `\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2161 assert(asNormalizedPath(`\foo\..`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2162 assert(asNormalizedPath(`\foo\../..`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2163
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2164 assert(asNormalizedPath(`foo\..\bar`).array == `bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2165 assert(asNormalizedPath(`foo\..\../bar`).array == `..\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2166
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2167 assert(asNormalizedPath(`..\foo`).array == `..\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2168 assert(asNormalizedPath(`..\..\foo`).array == `..\..\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2169 assert(asNormalizedPath(`..\foo\..\bar`).array == `..\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2170 assert(asNormalizedPath(`..\.\..\foo`).array == `..\..\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2171 assert(asNormalizedPath(`foo\bar\..`).array == `foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2172 assert(asNormalizedPath(`\foo\..\..`).array == `\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2173 assert(asNormalizedPath(`c:\foo\..\..`).array == `c:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2174
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2175 // Correct handling of non-root path with drive specifier
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2176 assert(asNormalizedPath(`c:foo`).array == `c:foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2177 assert(asNormalizedPath(`c:..\foo\.\..\bar`).array == `c:..\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2178
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2179 // The ultimate path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2180 assert(asNormalizedPath(`c:\foo\..\bar\\.\..\...\\\baz\\`).array == `c:\...\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2181 static assert(asNormalizedPath(`c:\foo\..\bar\\.\..\...\\\baz\\`).array == `c:\...\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2182 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2183 else static assert(false);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2184 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2185
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2186 /** Slice up a path into its elements.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2187
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2188 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2189 path = string or slicable random access range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2190
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2191 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2192 bidirectional range of slices of `path`
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2193 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2194 auto pathSplitter(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2195 if ((isRandomAccessRange!R && hasSlicing!R ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2196 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2197 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2198 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2199 static struct PathSplitter
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2200 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2201 @property bool empty() const { return pe == 0; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2202
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2203 @property R front()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2204 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2205 assert(!empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2206 return _path[fs .. fe];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2207 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2208
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2209 void popFront()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2210 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2211 assert(!empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2212 if (ps == pe)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2213 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2214 if (fs == bs && fe == be)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2215 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2216 pe = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2217 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2218 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2219 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2220 fs = bs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2221 fe = be;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2222 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2223 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2224 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2225 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2226 fs = ps;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2227 fe = fs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2228 while (fe < pe && !isDirSeparator(_path[fe]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2229 ++fe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2230 ps = ltrim(fe, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2231 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2232 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2233
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2234 @property R back()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2235 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2236 assert(!empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2237 return _path[bs .. be];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2238 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2239
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2240 void popBack()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2241 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2242 assert(!empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2243 if (ps == pe)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2244 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2245 if (fs == bs && fe == be)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2246 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2247 pe = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2248 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2249 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2250 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2251 bs = fs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2252 be = fe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2253 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2254 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2255 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2256 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2257 bs = pe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2258 be = bs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2259 while (bs > ps && !isDirSeparator(_path[bs - 1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2260 --bs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2261 pe = rtrim(ps, bs);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2262 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2263 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2264 @property auto save() { return this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2265
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2266
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2267 private:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2268 R _path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2269 size_t ps, pe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2270 size_t fs, fe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2271 size_t bs, be;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2272
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2273 this(R p)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2274 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2275 if (p.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2276 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2277 pe = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2278 return;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2279 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2280 _path = p;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2281
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2282 ps = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2283 pe = _path.length;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2284
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2285 // If path is rooted, first element is special
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2286 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2287 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2288 if (isUNC(_path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2289 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2290 auto i = uncRootLength(_path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2291 fs = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2292 fe = i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2293 ps = ltrim(fe, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2294 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2295 else if (isDriveRoot(_path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2296 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2297 fs = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2298 fe = 3;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2299 ps = ltrim(fe, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2300 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2301 else if (_path.length >= 1 && isDirSeparator(_path[0]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2302 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2303 fs = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2304 fe = 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2305 ps = ltrim(fe, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2306 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2307 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2308 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2309 assert(!isRooted(_path));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2310 popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2311 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2312 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2313 else version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2314 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2315 if (_path.length >= 1 && isDirSeparator(_path[0]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2316 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2317 fs = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2318 fe = 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2319 ps = ltrim(fe, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2320 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2321 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2322 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2323 popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2324 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2325 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2326 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2327
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2328 if (ps == pe)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2329 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2330 bs = fs;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2331 be = fe;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2332 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2333 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2334 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2335 pe = rtrim(ps, pe);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2336 popBack();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2337 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2338 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2339
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2340 size_t ltrim(size_t s, size_t e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2341 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2342 while (s < e && isDirSeparator(_path[s]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2343 ++s;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2344 return s;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2345 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2346
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2347 size_t rtrim(size_t s, size_t e)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2348 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2349 while (s < e && isDirSeparator(_path[e - 1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2350 --e;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2351 return e;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2352 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2353 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2354
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2355 return PathSplitter(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2356 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2357
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2358 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2359 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2360 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2361 import std.algorithm.comparison : equal;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2362 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2363
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2364 assert(equal(pathSplitter("/"), ["/"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2365 assert(equal(pathSplitter("/foo/bar"), ["/", "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2366 assert(equal(pathSplitter("foo/../bar//./"), ["foo", "..", "bar", "."]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2367
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2368 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2369 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2370 assert(equal(pathSplitter("//foo/bar"), ["/", "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2371 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2372
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2373 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2374 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2375 assert(equal(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2376 assert(equal(pathSplitter("c:"), ["c:"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2377 assert(equal(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2378 assert(equal(pathSplitter(`c:foo\bar`), ["c:foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2379 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2380 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2381
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2382 auto pathSplitter(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2383 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2384 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2385 return pathSplitter!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2386 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2387
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2388 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2389 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2390 import std.algorithm.comparison : equal;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2391 assert(testAliasedString!pathSplitter("/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2392 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2393
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2394 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2395 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2396 // equal2 verifies that the range is the same both ways, i.e.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2397 // through front/popFront and back/popBack.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2398 import std.algorithm;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2399 import std.range;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2400 bool equal2(R1, R2)(R1 r1, R2 r2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2401 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2402 static assert(isBidirectionalRange!R1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2403 return equal(r1, r2) && equal(retro(r1), retro(r2));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2404 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2405
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2406 assert(pathSplitter("").empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2407
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2408 // Root directories
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2409 assert(equal2(pathSplitter("/"), ["/"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2410 assert(equal2(pathSplitter("//"), ["/"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2411 assert(equal2(pathSplitter("///"w), ["/"w]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2412
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2413 // Absolute paths
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2414 assert(equal2(pathSplitter("/foo/bar".dup), ["/", "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2415
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2416 // General
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2417 assert(equal2(pathSplitter("foo/bar"d.dup), ["foo"d, "bar"d]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2418 assert(equal2(pathSplitter("foo//bar"), ["foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2419 assert(equal2(pathSplitter("foo/bar//"w), ["foo"w, "bar"w]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2420 assert(equal2(pathSplitter("foo/../bar//./"d), ["foo"d, ".."d, "bar"d, "."d]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2421
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2422 // save()
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2423 auto ps1 = pathSplitter("foo/bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2424 auto ps2 = ps1.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2425 ps1.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2426 assert(equal2(ps1, ["bar", "baz"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2427 assert(equal2(ps2, ["foo", "bar", "baz"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2428
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2429 // Platform specific
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2430 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2431 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2432 assert(equal2(pathSplitter("//foo/bar"w.dup), ["/"w, "foo"w, "bar"w]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2433 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2434 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2435 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2436 assert(equal2(pathSplitter(`\`), [`\`]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2437 assert(equal2(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2438 assert(equal2(pathSplitter("c:"), ["c:"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2439 assert(equal2(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2440 assert(equal2(pathSplitter(`c:foo\bar`), ["c:foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2441 assert(equal2(pathSplitter(`\\foo\bar`), [`\\foo\bar`]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2442 assert(equal2(pathSplitter(`\\foo\bar\\`), [`\\foo\bar`]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2443 assert(equal2(pathSplitter(`\\foo\bar\baz`), [`\\foo\bar`, "baz"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2444 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2445
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2446 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2447 assertCTFEable!(
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2448 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2449 assert(equal(pathSplitter("/foo/bar".dup), ["/", "foo", "bar"]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2450 });
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2451
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2452 static assert(is(typeof(pathSplitter!(const(char)[])(null).front) == const(char)[]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2453
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2454 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2455 assert(equal2(pathSplitter("foo/bar"d.byDchar), ["foo"d, "bar"d]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2456 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2457
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2458
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2459
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2460
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2461 /** Determines whether a path starts at a root directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2462
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2463 Params: path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2464 Returns: Whether a path starts at a root directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2465
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2466 On POSIX, this function returns true if and only if the path starts
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2467 with a slash (/).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2468 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2469 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2470 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2471 assert(isRooted("/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2472 assert(isRooted("/foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2473 assert(!isRooted("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2474 assert(!isRooted("../foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2475 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2476 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2477
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2478 On Windows, this function returns true if the path starts at
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2479 the root directory of the current drive, of some other drive,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2480 or of a network drive.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2481 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2482 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2483 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2484 assert(isRooted(`\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2485 assert(isRooted(`\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2486 assert(isRooted(`d:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2487 assert(isRooted(`\\foo\bar`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2488 assert(!isRooted("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2489 assert(!isRooted("d:foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2490 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2491 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2492 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2493 bool isRooted(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2494 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2495 is(StringTypeOf!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2496 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2497 if (path.length >= 1 && isDirSeparator(path[0])) return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2498 version (Posix) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2499 else version (Windows) return isAbsolute!(BaseOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2500 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2501
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2502
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2503 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2504 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2505 assert(isRooted("/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2506 assert(isRooted("/foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2507 assert(!isRooted("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2508 assert(!isRooted("../foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2509
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2510 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2511 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2512 assert(isRooted(`\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2513 assert(isRooted(`\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2514 assert(isRooted(`d:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2515 assert(isRooted(`\\foo\bar`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2516 assert(!isRooted("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2517 assert(!isRooted("d:foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2518 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2519
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2520 static assert(isRooted("/foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2521 static assert(!isRooted("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2522
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2523 static struct DirEntry { string s; alias s this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2524 assert(!isRooted(DirEntry("foo")));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2525 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2526
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2527
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2528
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2529
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2530 /** Determines whether a path is absolute or not.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2531
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2532 Params: path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2533
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2534 Returns: Whether a path is absolute or not.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2535
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2536 Example:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2537 On POSIX, an absolute path starts at the root directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2538 (In fact, $(D _isAbsolute) is just an alias for $(LREF isRooted).)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2539 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2540 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2541 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2542 assert(isAbsolute("/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2543 assert(isAbsolute("/foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2544 assert(!isAbsolute("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2545 assert(!isAbsolute("../foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2546 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2547 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2548
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2549 On Windows, an absolute path starts at the root directory of
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2550 a specific drive. Hence, it must start with $(D `d:\`) or $(D `d:/`),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2551 where $(D d) is the drive letter. Alternatively, it may be a
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2552 network path, i.e. a path starting with a double (back)slash.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2553 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2554 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2555 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2556 assert(isAbsolute(`d:\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2557 assert(isAbsolute(`d:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2558 assert(isAbsolute(`\\foo\bar`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2559 assert(!isAbsolute(`\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2560 assert(!isAbsolute(`\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2561 assert(!isAbsolute("d:foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2562 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2563 ---
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2564 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2565 version (StdDdoc)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2566 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2567 bool isAbsolute(R)(R path) pure nothrow @safe
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2568 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2569 is(StringTypeOf!R));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2570 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2571 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2572 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2573 bool isAbsolute(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2574 if (isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2575 is(StringTypeOf!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2576 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2577 return isDriveRoot!(BaseOf!R)(path) || isUNC!(BaseOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2578 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2579 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2580 else version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2581 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2582 alias isAbsolute = isRooted;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2583 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2584
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2585
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2586 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2587 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2588 assert(!isAbsolute("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2589 assert(!isAbsolute("../foo"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2590 static assert(!isAbsolute("foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2591
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2592 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2593 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2594 assert(isAbsolute("/"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2595 assert(isAbsolute("/foo".dup));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2596 static assert(isAbsolute("/foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2597 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2598
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2599 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2600 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2601 assert(isAbsolute("d:\\"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2602 assert(isAbsolute("d:\\foo"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2603 assert(isAbsolute("\\\\foo\\bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2604 assert(!isAbsolute("\\"w.dup));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2605 assert(!isAbsolute("\\foo"d.dup));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2606 assert(!isAbsolute("d:"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2607 assert(!isAbsolute("d:foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2608 static assert(isAbsolute(`d:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2609 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2610
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2611 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2612 auto r = MockRange!(immutable(char))(`../foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2613 assert(!r.isAbsolute());
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2614 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2615
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2616 static struct DirEntry { string s; alias s this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2617 assert(!isAbsolute(DirEntry("foo")));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2618 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2619
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2620
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2621
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2622
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2623 /** Transforms $(D path) into an absolute _path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2624
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2625 The following algorithm is used:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2626 $(OL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2627 $(LI If $(D path) is empty, return $(D null).)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2628 $(LI If $(D path) is already absolute, return it.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2629 $(LI Otherwise, append $(D path) to $(D base) and return
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2630 the result. If $(D base) is not specified, the current
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2631 working directory is used.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2632 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2633 The function allocates memory if and only if it gets to the third stage
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2634 of this algorithm.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2635
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2636 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2637 path = the relative path to transform
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2638 base = the base directory of the relative path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2639
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2640 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2641 string of transformed path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2642
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2643 Throws:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2644 $(D Exception) if the specified _base directory is not absolute.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2645
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2646 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2647 $(LREF asAbsolutePath) which does not allocate
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2648 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2649 string absolutePath(string path, lazy string base = getcwd())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2650 @safe pure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2651 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2652 import std.array : array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2653 if (path.empty) return null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2654 if (isAbsolute(path)) return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2655 auto baseVar = base;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2656 if (!isAbsolute(baseVar)) throw new Exception("Base directory must be absolute");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2657 return chainPath(baseVar, path).array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2658 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2659
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2660 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2661 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2662 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2663 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2664 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2665 assert(absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2666 assert(absolutePath("../file", "/foo/bar") == "/foo/bar/../file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2667 assert(absolutePath("/some/file", "/foo/bar") == "/some/file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2668 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2669
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2670 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2671 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2672 assert(absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2673 assert(absolutePath(`..\file`, `c:\foo\bar`) == `c:\foo\bar\..\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2674 assert(absolutePath(`c:\some\file`, `c:\foo\bar`) == `c:\some\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2675 assert(absolutePath(`\`, `c:\`) == `c:\`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2676 assert(absolutePath(`\some\file`, `c:\foo\bar`) == `c:\some\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2677 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2678 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2679
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2680 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2681 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2682 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2683 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2684 static assert(absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2685 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2686
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2687 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2688 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2689 static assert(absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2690 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2691
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2692 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2693 assertThrown(absolutePath("bar", "foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2694 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2695
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2696 /** Transforms $(D path) into an absolute _path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2697
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2698 The following algorithm is used:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2699 $(OL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2700 $(LI If $(D path) is empty, return $(D null).)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2701 $(LI If $(D path) is already absolute, return it.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2702 $(LI Otherwise, append $(D path) to the current working directory,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2703 which allocates memory.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2704 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2705
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2706 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2707 path = the relative path to transform
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2708
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2709 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2710 the transformed path as a lazy range
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2711
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2712 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2713 $(LREF absolutePath) which returns an allocated string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2714 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2715 auto asAbsolutePath(R)(R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2716 if ((isRandomAccessRange!R && isSomeChar!(ElementType!R) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2717 isNarrowString!R) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2718 !isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2719 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2720 import std.file : getcwd;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2721 string base = null;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2722 if (!path.empty && !isAbsolute(path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2723 base = getcwd();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2724 return chainPath(base, path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2725 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2726
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2727 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2728 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2729 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2730 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2731 assert(asAbsolutePath(cast(string) null).array == "");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2732 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2733 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2734 assert(asAbsolutePath("/foo").array == "/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2735 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2736 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2737 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2738 assert(asAbsolutePath("c:/foo").array == "c:/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2739 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2740 asAbsolutePath("foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2741 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2742
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2743 auto asAbsolutePath(R)(auto ref R path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2744 if (isConvertibleToString!R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2745 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2746 return asAbsolutePath!(StringTypeOf!R)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2747 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2748
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2749 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2750 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2751 assert(testAliasedString!asAbsolutePath(null));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2752 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2753
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2754 /** Translates $(D path) into a relative _path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2755
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2756 The returned _path is relative to $(D base), which is by default
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2757 taken to be the current working directory. If specified,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2758 $(D base) must be an absolute _path, and it is always assumed
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2759 to refer to a directory. If $(D path) and $(D base) refer to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2760 the same directory, the function returns $(D `.`).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2761
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2762 The following algorithm is used:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2763 $(OL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2764 $(LI If $(D path) is a relative directory, return it unaltered.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2765 $(LI Find a common root between $(D path) and $(D base).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2766 If there is no common root, return $(D path) unaltered.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2767 $(LI Prepare a string with as many $(D `../`) or $(D `..\`) as
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2768 necessary to reach the common root from base path.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2769 $(LI Append the remaining segments of $(D path) to the string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2770 and return.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2771 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2772
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2773 In the second step, path components are compared using $(D filenameCmp!cs),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2774 where $(D cs) is an optional template parameter determining whether
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2775 the comparison is case sensitive or not. See the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2776 $(LREF filenameCmp) documentation for details.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2777
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2778 This function allocates memory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2779
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2780 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2781 cs = Whether matching path name components against the base path should
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2782 be case-sensitive or not.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2783 path = A path name.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2784 base = The base path to construct the relative path from.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2785
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2786 Returns: The relative path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2787
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2788 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2789 $(LREF asRelativePath) which does not allocate memory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2790
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2791 Throws:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2792 $(D Exception) if the specified _base directory is not absolute.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2793 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2794 string relativePath(CaseSensitive cs = CaseSensitive.osDefault)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2795 (string path, lazy string base = getcwd())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2796 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2797 if (!isAbsolute(path))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2798 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2799 auto baseVar = base;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2800 if (!isAbsolute(baseVar))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2801 throw new Exception("Base directory must be absolute");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2802
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2803 import std.conv : to;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2804 return asRelativePath!cs(path, baseVar).to!string;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2805 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2806
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2807 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2808 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2809 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2810 assert(relativePath("foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2811
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2812 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2813 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2814 assert(relativePath("foo", "/bar") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2815 assert(relativePath("/foo/bar", "/foo/bar") == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2816 assert(relativePath("/foo/bar", "/foo/baz") == "../bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2817 assert(relativePath("/foo/bar/baz", "/foo/woo/wee") == "../../bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2818 assert(relativePath("/foo/bar/baz", "/foo/bar") == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2819 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2820 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2821 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2822 assert(relativePath("foo", `c:\bar`) == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2823 assert(relativePath(`c:\foo\bar`, `c:\foo\bar`) == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2824 assert(relativePath(`c:\foo\bar`, `c:\foo\baz`) == `..\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2825 assert(relativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`) == `..\..\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2826 assert(relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2827 assert(relativePath(`c:\foo\bar`, `d:\foo`) == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2828 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2829 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2830
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2831 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2832 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2833 import std.exception;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2834 assert(relativePath("foo") == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2835 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2836 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2837 relativePath("/foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2838 assert(relativePath("/foo/bar", "/foo/baz") == "../bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2839 assertThrown(relativePath("/foo", "bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2840 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2841 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2842 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2843 relativePath(`\foo`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2844 assert(relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2845 assertThrown(relativePath(`c:\foo`, "bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2846 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2847 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2848 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2849
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2850 /** Transforms `path` into a _path relative to `base`.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2851
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2852 The returned _path is relative to `base`, which is usually
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2853 the current working directory.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2854 `base` must be an absolute _path, and it is always assumed
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2855 to refer to a directory. If `path` and `base` refer to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2856 the same directory, the function returns `'.'`.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2857
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2858 The following algorithm is used:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2859 $(OL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2860 $(LI If `path` is a relative directory, return it unaltered.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2861 $(LI Find a common root between `path` and `base`.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2862 If there is no common root, return `path` unaltered.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2863 $(LI Prepare a string with as many `../` or `..\` as
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2864 necessary to reach the common root from base path.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2865 $(LI Append the remaining segments of `path` to the string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2866 and return.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2867 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2868
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2869 In the second step, path components are compared using `filenameCmp!cs`,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2870 where `cs` is an optional template parameter determining whether
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2871 the comparison is case sensitive or not. See the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2872 $(LREF filenameCmp) documentation for details.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2873
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2874 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2875 path = _path to transform
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2876 base = absolute path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2877 cs = whether filespec comparisons are sensitive or not; defaults to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2878 `CaseSensitive.osDefault`
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2879
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2880 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2881 a random access range of the transformed _path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2882
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2883 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2884 $(LREF relativePath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2885 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2886 auto asRelativePath(CaseSensitive cs = CaseSensitive.osDefault, R1, R2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2887 (R1 path, R2 base)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2888 if ((isNarrowString!R1 ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2889 (isRandomAccessRange!R1 && hasSlicing!R1 && isSomeChar!(ElementType!R1)) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2890 !isConvertibleToString!R1) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2891 (isNarrowString!R2 ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2892 (isRandomAccessRange!R2 && hasSlicing!R2 && isSomeChar!(ElementType!R2)) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2893 !isConvertibleToString!R2))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2894 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2895 bool choosePath = !isAbsolute(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2896
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2897 // Find common root with current working directory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2898
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2899 auto basePS = pathSplitter(base);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2900 auto pathPS = pathSplitter(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2901 choosePath |= filenameCmp!cs(basePS.front, pathPS.front) != 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2902
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2903 basePS.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2904 pathPS.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2905
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2906 import std.algorithm.comparison : mismatch;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2907 import std.algorithm.iteration : joiner;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2908 import std.array : array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2909 import std.range.primitives : walkLength;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2910 import std.range : repeat, chain, choose;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2911 import std.utf : byCodeUnit, byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2912
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2913 // Remove matching prefix from basePS and pathPS
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2914 auto tup = mismatch!((a, b) => filenameCmp!cs(a, b) == 0)(basePS, pathPS);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2915 basePS = tup[0];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2916 pathPS = tup[1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2917
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2918 string sep;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2919 if (basePS.empty && pathPS.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2920 sep = "."; // if base == path, this is the return
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2921 else if (!basePS.empty && !pathPS.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2922 sep = dirSeparator;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2923
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2924 // Append as many "../" as necessary to reach common base from path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2925 auto r1 = ".."
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2926 .byChar
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2927 .repeat(basePS.walkLength())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2928 .joiner(dirSeparator.byChar);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2929
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2930 auto r2 = pathPS
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2931 .joiner(dirSeparator.byChar)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2932 .byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2933
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2934 // Return (r1 ~ sep ~ r2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2935 return choose(choosePath, path.byCodeUnit, chain(r1, sep.byChar, r2));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2936 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2937
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2938 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2939 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2940 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2941 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2942 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2943 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2944 assert(asRelativePath("foo", "/bar").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2945 assert(asRelativePath("/foo/bar", "/foo/bar").array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2946 assert(asRelativePath("/foo/bar", "/foo/baz").array == "../bar");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2947 assert(asRelativePath("/foo/bar/baz", "/foo/woo/wee").array == "../../bar/baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2948 assert(asRelativePath("/foo/bar/baz", "/foo/bar").array == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2949 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2950 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2951 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2952 assert(asRelativePath("foo", `c:\bar`).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2953 assert(asRelativePath(`c:\foo\bar`, `c:\foo\bar`).array == ".");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2954 assert(asRelativePath(`c:\foo\bar`, `c:\foo\baz`).array == `..\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2955 assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2956 assert(asRelativePath(`c:/foo/bar/baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2957 assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\bar`).array == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2958 assert(asRelativePath(`c:\foo\bar`, `d:\foo`).array == `c:\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2959 assert(asRelativePath(`\\foo\bar`, `c:\foo`).array == `\\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2960 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2961 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2962 static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2963 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2964
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2965 auto asRelativePath(CaseSensitive cs = CaseSensitive.osDefault, R1, R2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2966 (auto ref R1 path, auto ref R2 base)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2967 if (isConvertibleToString!R1 || isConvertibleToString!R2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2968 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2969 import std.meta : staticMap;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2970 alias Types = staticMap!(convertToString, R1, R2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2971 return asRelativePath!(cs, Types)(path, base);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2972 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2973
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2974 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2975 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2976 import std.array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2977 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2978 assert(asRelativePath(TestAliasedString("foo"), TestAliasedString("/bar")).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2979 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2980 assert(asRelativePath(TestAliasedString("foo"), TestAliasedString(`c:\bar`)).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2981 assert(asRelativePath(TestAliasedString("foo"), "bar").array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2982 assert(asRelativePath("foo", TestAliasedString("bar")).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2983 assert(asRelativePath(TestAliasedString("foo"), TestAliasedString("bar")).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2984 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2985 assert(asRelativePath("foo"d.byDchar, TestAliasedString("bar")).array == "foo");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2986 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2987
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2988 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2989 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2990 import std.array, std.utf : bCU=byCodeUnit;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2991 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2992 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2993 assert(asRelativePath("/foo/bar/baz".bCU, "/foo/bar".bCU).array == "baz");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2994 assert(asRelativePath("/foo/bar/baz"w.bCU, "/foo/bar"w.bCU).array == "baz"w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2995 assert(asRelativePath("/foo/bar/baz"d.bCU, "/foo/bar"d.bCU).array == "baz"d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2996 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2997 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2998 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
2999 assert(asRelativePath(`\\foo\bar`.bCU, `c:\foo`.bCU).array == `\\foo\bar`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3000 assert(asRelativePath(`\\foo\bar`w.bCU, `c:\foo`w.bCU).array == `\\foo\bar`w);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3001 assert(asRelativePath(`\\foo\bar`d.bCU, `c:\foo`d.bCU).array == `\\foo\bar`d);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3002 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3003 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3004
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3005 /** Compares filename characters.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3006
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3007 This function can perform a case-sensitive or a case-insensitive
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3008 comparison. This is controlled through the $(D cs) template parameter
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3009 which, if not specified, is given by $(LREF CaseSensitive)$(D .osDefault).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3010
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3011 On Windows, the backslash and slash characters ($(D `\`) and $(D `/`))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3012 are considered equal.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3013
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3014 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3015 cs = Case-sensitivity of the comparison.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3016 a = A filename character.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3017 b = A filename character.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3018
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3019 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3020 $(D < 0) if $(D a < b),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3021 $(D 0) if $(D a == b), and
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3022 $(D > 0) if $(D a > b).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3023 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3024 int filenameCharCmp(CaseSensitive cs = CaseSensitive.osDefault)(dchar a, dchar b)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3025 @safe pure nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3026 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3027 if (isDirSeparator(a) && isDirSeparator(b)) return 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3028 static if (!cs)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3029 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3030 import std.uni : toLower;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3031 a = toLower(a);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3032 b = toLower(b);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3033 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3034 return cast(int)(a - b);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3035 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3036
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3037 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3038 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3039 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3040 assert(filenameCharCmp('a', 'a') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3041 assert(filenameCharCmp('a', 'b') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3042 assert(filenameCharCmp('b', 'a') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3043
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3044 version (linux)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3045 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3046 // Same as calling filenameCharCmp!(CaseSensitive.yes)(a, b)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3047 assert(filenameCharCmp('A', 'a') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3048 assert(filenameCharCmp('a', 'A') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3049 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3050 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3051 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3052 // Same as calling filenameCharCmp!(CaseSensitive.no)(a, b)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3053 assert(filenameCharCmp('a', 'A') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3054 assert(filenameCharCmp('a', 'B') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3055 assert(filenameCharCmp('A', 'b') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3056 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3057 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3058
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3059 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3060 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3061 assert(filenameCharCmp!(CaseSensitive.yes)('A', 'a') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3062 assert(filenameCharCmp!(CaseSensitive.yes)('a', 'A') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3063
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3064 assert(filenameCharCmp!(CaseSensitive.no)('a', 'a') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3065 assert(filenameCharCmp!(CaseSensitive.no)('a', 'b') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3066 assert(filenameCharCmp!(CaseSensitive.no)('b', 'a') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3067 assert(filenameCharCmp!(CaseSensitive.no)('A', 'a') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3068 assert(filenameCharCmp!(CaseSensitive.no)('a', 'A') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3069 assert(filenameCharCmp!(CaseSensitive.no)('a', 'B') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3070 assert(filenameCharCmp!(CaseSensitive.no)('B', 'a') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3071 assert(filenameCharCmp!(CaseSensitive.no)('A', 'b') < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3072 assert(filenameCharCmp!(CaseSensitive.no)('b', 'A') > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3073
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3074 version (Posix) assert(filenameCharCmp('\\', '/') != 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3075 version (Windows) assert(filenameCharCmp('\\', '/') == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3076 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3077
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3078
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3079 /** Compares file names and returns
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3080
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3081 Individual characters are compared using $(D filenameCharCmp!cs),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3082 where $(D cs) is an optional template parameter determining whether
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3083 the comparison is case sensitive or not.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3084
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3085 Treatment of invalid UTF encodings is implementation defined.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3086
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3087 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3088 cs = case sensitivity
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3089 filename1 = range for first file name
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3090 filename2 = range for second file name
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3091
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3092 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3093 $(D < 0) if $(D filename1 < filename2),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3094 $(D 0) if $(D filename1 == filename2) and
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3095 $(D > 0) if $(D filename1 > filename2).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3096
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3097 See_Also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3098 $(LREF filenameCharCmp)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3099 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3100 int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3101 (Range1 filename1, Range2 filename2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3102 if (isInputRange!Range1 && !isInfinite!Range1 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3103 isSomeChar!(ElementEncodingType!Range1) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3104 !isConvertibleToString!Range1 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3105 isInputRange!Range2 && !isInfinite!Range2 &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3106 isSomeChar!(ElementEncodingType!Range2) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3107 !isConvertibleToString!Range2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3108 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3109 alias C1 = Unqual!(ElementEncodingType!Range1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3110 alias C2 = Unqual!(ElementEncodingType!Range2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3111
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3112 static if (!cs && (C1.sizeof < 4 || C2.sizeof < 4) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3113 C1.sizeof != C2.sizeof)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3114 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3115 // Case insensitive - decode so case is checkable
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3116 // Different char sizes - decode to bring to common type
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3117 import std.utf : byDchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3118 return filenameCmp!cs(filename1.byDchar, filename2.byDchar);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3119 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3120 else static if (isSomeString!Range1 && C1.sizeof < 4 ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3121 isSomeString!Range2 && C2.sizeof < 4)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3122 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3123 // Avoid autodecoding
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3124 import std.utf : byCodeUnit;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3125 return filenameCmp!cs(filename1.byCodeUnit, filename2.byCodeUnit);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3126 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3127 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3128 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3129 for (;;)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3130 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3131 if (filename1.empty) return -(cast(int) !filename2.empty);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3132 if (filename2.empty) return 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3133 const c = filenameCharCmp!cs(filename1.front, filename2.front);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3134 if (c != 0) return c;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3135 filename1.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3136 filename2.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3137 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3138 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3139 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3140
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3141 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3142 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3143 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3144 assert(filenameCmp("abc", "abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3145 assert(filenameCmp("abc", "abd") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3146 assert(filenameCmp("abc", "abb") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3147 assert(filenameCmp("abc", "abcd") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3148 assert(filenameCmp("abcd", "abc") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3149
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3150 version (linux)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3151 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3152 // Same as calling filenameCmp!(CaseSensitive.yes)(filename1, filename2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3153 assert(filenameCmp("Abc", "abc") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3154 assert(filenameCmp("abc", "Abc") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3155 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3156 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3157 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3158 // Same as calling filenameCmp!(CaseSensitive.no)(filename1, filename2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3159 assert(filenameCmp("Abc", "abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3160 assert(filenameCmp("abc", "Abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3161 assert(filenameCmp("Abc", "abD") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3162 assert(filenameCmp("abc", "AbB") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3163 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3164 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3165
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3166 int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3167 (auto ref Range1 filename1, auto ref Range2 filename2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3168 if (isConvertibleToString!Range1 || isConvertibleToString!Range2)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3169 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3170 import std.meta : staticMap;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3171 alias Types = staticMap!(convertToString, Range1, Range2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3172 return filenameCmp!(cs, Types)(filename1, filename2);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3173 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3174
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3175 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3176 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3177 assert(filenameCmp!(CaseSensitive.yes)(TestAliasedString("Abc"), "abc") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3178 assert(filenameCmp!(CaseSensitive.yes)("Abc", TestAliasedString("abc")) < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3179 assert(filenameCmp!(CaseSensitive.yes)(TestAliasedString("Abc"), TestAliasedString("abc")) < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3180 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3181
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3182 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3183 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3184 assert(filenameCmp!(CaseSensitive.yes)("Abc", "abc") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3185 assert(filenameCmp!(CaseSensitive.yes)("abc", "Abc") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3186
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3187 assert(filenameCmp!(CaseSensitive.no)("abc", "abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3188 assert(filenameCmp!(CaseSensitive.no)("abc", "abd") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3189 assert(filenameCmp!(CaseSensitive.no)("abc", "abb") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3190 assert(filenameCmp!(CaseSensitive.no)("abc", "abcd") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3191 assert(filenameCmp!(CaseSensitive.no)("abcd", "abc") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3192 assert(filenameCmp!(CaseSensitive.no)("Abc", "abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3193 assert(filenameCmp!(CaseSensitive.no)("abc", "Abc") == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3194 assert(filenameCmp!(CaseSensitive.no)("Abc", "abD") < 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3195 assert(filenameCmp!(CaseSensitive.no)("abc", "AbB") > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3196
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3197 version (Posix) assert(filenameCmp(`abc\def`, `abc/def`) != 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3198 version (Windows) assert(filenameCmp(`abc\def`, `abc/def`) == 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3199 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3200
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3201 /** Matches a pattern against a path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3202
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3203 Some characters of pattern have a special meaning (they are
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3204 $(I meta-characters)) and can't be escaped. These are:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3205
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3206 $(BOOKTABLE,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3207 $(TR $(TD $(D *))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3208 $(TD Matches 0 or more instances of any character.))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3209 $(TR $(TD $(D ?))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3210 $(TD Matches exactly one instance of any character.))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3211 $(TR $(TD $(D [)$(I chars)$(D ]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3212 $(TD Matches one instance of any character that appears
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3213 between the brackets.))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3214 $(TR $(TD $(D [!)$(I chars)$(D ]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3215 $(TD Matches one instance of any character that does not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3216 appear between the brackets after the exclamation mark.))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3217 $(TR $(TD $(D {)$(I string1)$(D ,)$(I string2)$(D ,)&hellip;$(D }))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3218 $(TD Matches either of the specified strings.))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3219 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3220
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3221 Individual characters are compared using $(D filenameCharCmp!cs),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3222 where $(D cs) is an optional template parameter determining whether
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3223 the comparison is case sensitive or not. See the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3224 $(LREF filenameCharCmp) documentation for details.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3225
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3226 Note that directory
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3227 separators and dots don't stop a meta-character from matching
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3228 further portions of the path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3229
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3230 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3231 cs = Whether the matching should be case-sensitive
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3232 path = The path to be matched against
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3233 pattern = The glob pattern
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3234
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3235 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3236 $(D true) if pattern matches path, $(D false) otherwise.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3237
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3238 See_also:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3239 $(LINK2 http://en.wikipedia.org/wiki/Glob_%28programming%29,Wikipedia: _glob (programming))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3240 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3241 bool globMatch(CaseSensitive cs = CaseSensitive.osDefault, C, Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3242 (Range path, const(C)[] pattern)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3243 @safe pure nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3244 if (isForwardRange!Range && !isInfinite!Range &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3245 isSomeChar!(ElementEncodingType!Range) && !isConvertibleToString!Range &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3246 isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range)))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3247 in
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3248 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3249 // Verify that pattern[] is valid
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3250 import std.algorithm.searching : balancedParens;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3251 assert(balancedParens(pattern, '[', ']', 0));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3252 assert(balancedParens(pattern, '{', '}', 0));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3253 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3254 body
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3255 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3256 alias RC = Unqual!(ElementEncodingType!Range);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3257
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3258 static if (RC.sizeof == 1 && isSomeString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3259 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3260 import std.utf : byChar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3261 return globMatch!cs(path.byChar, pattern);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3262 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3263 else static if (RC.sizeof == 2 && isSomeString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3264 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3265 import std.utf : byWchar;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3266 return globMatch!cs(path.byWchar, pattern);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3267 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3268 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3269 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3270 C[] pattmp;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3271 foreach (ref pi; 0 .. pattern.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3272 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3273 const pc = pattern[pi];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3274 switch (pc)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3275 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3276 case '*':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3277 if (pi + 1 == pattern.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3278 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3279 for (; !path.empty; path.popFront())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3280 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3281 auto p = path.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3282 if (globMatch!(cs, C)(p,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3283 pattern[pi + 1 .. pattern.length]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3284 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3285 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3286 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3287
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3288 case '?':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3289 if (path.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3290 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3291 path.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3292 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3293
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3294 case '[':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3295 if (path.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3296 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3297 auto nc = path.front;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3298 path.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3299 auto not = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3300 ++pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3301 if (pattern[pi] == '!')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3302 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3303 not = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3304 ++pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3305 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3306 auto anymatch = false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3307 while (1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3308 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3309 const pc2 = pattern[pi];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3310 if (pc2 == ']')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3311 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3312 if (!anymatch && (filenameCharCmp!cs(nc, pc2) == 0))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3313 anymatch = true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3314 ++pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3315 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3316 if (anymatch == not)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3317 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3318 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3319
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3320 case '{':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3321 // find end of {} section
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3322 auto piRemain = pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3323 for (; piRemain < pattern.length
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3324 && pattern[piRemain] != '}'; ++piRemain)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3325 { }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3326
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3327 if (piRemain < pattern.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3328 ++piRemain;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3329 ++pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3330
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3331 while (pi < pattern.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3332 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3333 const pi0 = pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3334 C pc3 = pattern[pi];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3335 // find end of current alternative
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3336 for (; pi < pattern.length && pc3 != '}' && pc3 != ','; ++pi)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3337 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3338 pc3 = pattern[pi];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3339 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3340
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3341 auto p = path.save;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3342 if (pi0 == pi)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3343 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3344 if (globMatch!(cs, C)(p, pattern[piRemain..$]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3345 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3346 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3347 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3348 ++pi;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3349 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3350 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3351 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3352 /* Match for:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3353 * pattern[pi0 .. pi-1] ~ pattern[piRemain..$]
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3354 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3355 if (pattmp is null)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3356 // Allocate this only once per function invocation.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3357 // Should do it with malloc/free, but that would make it impure.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3358 pattmp = new C[pattern.length];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3359
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3360 const len1 = pi - 1 - pi0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3361 pattmp[0 .. len1] = pattern[pi0 .. pi - 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3362
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3363 const len2 = pattern.length - piRemain;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3364 pattmp[len1 .. len1 + len2] = pattern[piRemain .. $];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3365
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3366 if (globMatch!(cs, C)(p, pattmp[0 .. len1 + len2]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3367 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3368 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3369 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3370 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3371 if (pc3 == '}')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3372 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3373 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3374 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3375 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3376 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3377
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3378 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3379 if (path.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3380 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3381 if (filenameCharCmp!cs(pc, path.front) != 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3382 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3383 path.popFront();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3384 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3385 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3386 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3387 return path.empty;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3388 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3389 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3390
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3391 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3392 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3393 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3394 assert(globMatch("foo.bar", "*"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3395 assert(globMatch("foo.bar", "*.*"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3396 assert(globMatch(`foo/foo\bar`, "f*b*r"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3397 assert(globMatch("foo.bar", "f???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3398 assert(globMatch("foo.bar", "[fg]???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3399 assert(globMatch("foo.bar", "[!gh]*bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3400 assert(globMatch("bar.fooz", "bar.{foo,bif}z"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3401 assert(globMatch("bar.bifz", "bar.{foo,bif}z"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3402
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3403 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3404 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3405 // Same as calling globMatch!(CaseSensitive.no)(path, pattern)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3406 assert(globMatch("foo", "Foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3407 assert(globMatch("Goo.bar", "[fg]???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3408 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3409 version (linux)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3410 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3411 // Same as calling globMatch!(CaseSensitive.yes)(path, pattern)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3412 assert(!globMatch("foo", "Foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3413 assert(!globMatch("Goo.bar", "[fg]???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3414 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3415 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3416
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3417 bool globMatch(CaseSensitive cs = CaseSensitive.osDefault, C, Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3418 (auto ref Range path, const(C)[] pattern)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3419 @safe pure nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3420 if (isConvertibleToString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3421 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3422 return globMatch!(cs, C, StringTypeOf!Range)(path, pattern);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3423 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3424
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3425 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3426 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3427 assert(testAliasedString!globMatch("foo.bar", "*"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3428 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3429
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3430 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3431 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3432 assert(globMatch!(CaseSensitive.no)("foo", "Foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3433 assert(!globMatch!(CaseSensitive.yes)("foo", "Foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3434
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3435 assert(globMatch("foo", "*"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3436 assert(globMatch("foo.bar"w, "*"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3437 assert(globMatch("foo.bar"d, "*.*"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3438 assert(globMatch("foo.bar", "foo*"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3439 assert(globMatch("foo.bar"w, "f*bar"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3440 assert(globMatch("foo.bar"d, "f*b*r"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3441 assert(globMatch("foo.bar", "f???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3442 assert(globMatch("foo.bar"w, "[fg]???bar"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3443 assert(globMatch("foo.bar"d, "[!gh]*bar"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3444
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3445 assert(!globMatch("foo", "bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3446 assert(!globMatch("foo"w, "*.*"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3447 assert(!globMatch("foo.bar"d, "f*baz"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3448 assert(!globMatch("foo.bar", "f*b*x"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3449 assert(!globMatch("foo.bar", "[gh]???bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3450 assert(!globMatch("foo.bar"w, "[!fg]*bar"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3451 assert(!globMatch("foo.bar"d, "[fg]???baz"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3452 assert(!globMatch("foo.di", "*.d")); // test issue 6634: triggered bad assertion
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3453
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3454 assert(globMatch("foo.bar", "{foo,bif}.bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3455 assert(globMatch("bif.bar"w, "{foo,bif}.bar"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3456
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3457 assert(globMatch("bar.foo"d, "bar.{foo,bif}"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3458 assert(globMatch("bar.bif", "bar.{foo,bif}"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3459
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3460 assert(globMatch("bar.fooz"w, "bar.{foo,bif}z"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3461 assert(globMatch("bar.bifz"d, "bar.{foo,bif}z"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3462
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3463 assert(globMatch("bar.foo", "bar.{biz,,baz}foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3464 assert(globMatch("bar.foo"w, "bar.{biz,}foo"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3465 assert(globMatch("bar.foo"d, "bar.{,biz}foo"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3466 assert(globMatch("bar.foo", "bar.{}foo"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3467
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3468 assert(globMatch("bar.foo"w, "bar.{ar,,fo}o"w));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3469 assert(globMatch("bar.foo"d, "bar.{,ar,fo}o"d));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3470 assert(globMatch("bar.o", "bar.{,ar,fo}o"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3471
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3472 assert(!globMatch("foo", "foo?"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3473 assert(!globMatch("foo", "foo[]"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3474 assert(!globMatch("foo", "foob"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3475 assert(!globMatch("foo", "foo{b}"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3476
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3477
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3478 static assert(globMatch("foo.bar", "[!gh]*bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3479 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3480
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3481
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3482
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3483
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3484 /** Checks that the given file or directory name is valid.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3485
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3486 The maximum length of $(D filename) is given by the constant
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3487 $(D core.stdc.stdio.FILENAME_MAX). (On Windows, this number is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3488 defined as the maximum number of UTF-16 code points, and the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3489 test will therefore only yield strictly correct results when
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3490 $(D filename) is a string of $(D wchar)s.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3491
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3492 On Windows, the following criteria must be satisfied
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3493 ($(LINK2 http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx,source)):
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3494 $(UL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3495 $(LI $(D filename) must not contain any characters whose integer
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3496 representation is in the range 0-31.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3497 $(LI $(D filename) must not contain any of the following $(I reserved
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3498 characters): <>:"/\|?*)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3499 $(LI $(D filename) may not end with a space ($(D ' ')) or a period
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3500 ($(D '.')).)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3501 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3502
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3503 On POSIX, $(D filename) may not contain a forward slash ($(D '/')) or
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3504 the null character ($(D '\0')).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3505
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3506 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3507 filename = string to check
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3508
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3509 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3510 $(D true) if and only if $(D filename) is not
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3511 empty, not too long, and does not contain invalid characters.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3512
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3513 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3514 bool isValidFilename(Range)(Range filename)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3515 if ((isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && isSomeChar!(ElementEncodingType!Range) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3516 isNarrowString!Range) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3517 !isConvertibleToString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3518 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3519 import core.stdc.stdio : FILENAME_MAX;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3520 if (filename.length == 0 || filename.length >= FILENAME_MAX) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3521 foreach (c; filename)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3522 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3523 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3524 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3525 switch (c)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3526 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3527 case 0:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3528 ..
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3529 case 31:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3530 case '<':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3531 case '>':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3532 case ':':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3533 case '"':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3534 case '/':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3535 case '\\':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3536 case '|':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3537 case '?':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3538 case '*':
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3539 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3540
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3541 default:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3542 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3543 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3544 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3545 else version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3546 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3547 if (c == 0 || c == '/') return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3548 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3549 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3550 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3551 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3552 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3553 auto last = filename[filename.length - 1];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3554 if (last == '.' || last == ' ') return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3555 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3556
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3557 // All criteria passed
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3558 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3559 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3560
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3561 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3562 @safe pure @nogc nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3563 unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3564 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3565 import std.utf : byCodeUnit;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3566
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3567 assert(isValidFilename("hello.exe".byCodeUnit));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3568 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3569
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3570 bool isValidFilename(Range)(auto ref Range filename)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3571 if (isConvertibleToString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3572 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3573 return isValidFilename!(StringTypeOf!Range)(filename);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3574 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3575
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3576 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3577 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3578 assert(testAliasedString!isValidFilename("hello.exe"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3579 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3580
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3581 @safe pure
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3582 unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3583 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3584 import std.conv;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3585 auto valid = ["foo"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3586 auto invalid = ["", "foo\0bar", "foo/bar"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3587 auto pfdep = [`foo\bar`, "*.txt"];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3588 version (Windows) invalid ~= pfdep;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3589 else version (Posix) valid ~= pfdep;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3590 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3591
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3592 import std.meta : AliasSeq;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3593 foreach (T; AliasSeq!(char[], const(char)[], string, wchar[],
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3594 const(wchar)[], wstring, dchar[], const(dchar)[], dstring))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3595 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3596 foreach (fn; valid)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3597 assert(isValidFilename(to!T(fn)));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3598 foreach (fn; invalid)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3599 assert(!isValidFilename(to!T(fn)));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3600 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3601
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3602 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3603 auto r = MockRange!(immutable(char))(`dir/file.d`);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3604 assert(!isValidFilename(r));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3605 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3606
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3607 static struct DirEntry { string s; alias s this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3608 assert(isValidFilename(DirEntry("file.ext")));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3609
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3610 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3611 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3612 immutable string cases = "<>:\"/\\|?*";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3613 foreach (i; 0 .. 31 + cases.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3614 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3615 char[3] buf;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3616 buf[0] = 'a';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3617 buf[1] = i <= 31 ? cast(char) i : cases[i - 32];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3618 buf[2] = 'b';
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3619 assert(!isValidFilename(buf[]));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3620 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3621 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3622 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3623
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3624
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3625
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3626 /** Checks whether $(D path) is a valid _path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3627
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3628 Generally, this function checks that $(D path) is not empty, and that
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3629 each component of the path either satisfies $(LREF isValidFilename)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3630 or is equal to $(D ".") or $(D "..").
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3631
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3632 $(B It does $(I not) check whether the _path points to an existing file
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3633 or directory; use $(REF exists, std,file) for this purpose.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3634
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3635 On Windows, some special rules apply:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3636 $(UL
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3637 $(LI If the second character of $(D path) is a colon ($(D ':')),
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3638 the first character is interpreted as a drive letter, and
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3639 must be in the range A-Z (case insensitive).)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3640 $(LI If $(D path) is on the form $(D `\\$(I server)\$(I share)\...`)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3641 (UNC path), $(LREF isValidFilename) is applied to $(I server)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3642 and $(I share) as well.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3643 $(LI If $(D path) starts with $(D `\\?\`) (long UNC path), the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3644 only requirement for the rest of the string is that it does
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3645 not contain the null character.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3646 $(LI If $(D path) starts with $(D `\\.\`) (Win32 device namespace)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3647 this function returns $(D false); such paths are beyond the scope
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3648 of this module.)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3649 )
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3650
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3651 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3652 path = string or Range of characters to check
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3653
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3654 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3655 true if $(D path) is a valid _path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3656 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3657 bool isValidPath(Range)(Range path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3658 if ((isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && isSomeChar!(ElementEncodingType!Range) ||
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3659 isNarrowString!Range) &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3660 !isConvertibleToString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3661 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3662 alias C = Unqual!(ElementEncodingType!Range);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3663
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3664 if (path.empty) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3665
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3666 // Check whether component is "." or "..", or whether it satisfies
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3667 // isValidFilename.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3668 bool isValidComponent(Range component)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3669 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3670 assert(component.length > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3671 if (component[0] == '.')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3672 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3673 if (component.length == 1) return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3674 else if (component.length == 2 && component[1] == '.') return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3675 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3676 return isValidFilename(component);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3677 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3678
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3679 if (path.length == 1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3680 return isDirSeparator(path[0]) || isValidComponent(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3681
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3682 Range remainder;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3683 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3684 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3685 if (isDirSeparator(path[0]) && isDirSeparator(path[1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3686 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3687 // Some kind of UNC path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3688 if (path.length < 5)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3689 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3690 // All valid UNC paths must have at least 5 characters
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3691 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3692 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3693 else if (path[2] == '?')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3694 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3695 // Long UNC path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3696 if (!isDirSeparator(path[3])) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3697 foreach (c; path[4 .. $])
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3698 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3699 if (c == '\0') return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3700 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3701 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3702 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3703 else if (path[2] == '.')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3704 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3705 // Win32 device namespace not supported
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3706 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3707 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3708 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3709 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3710 // Normal UNC path, i.e. \\server\share\...
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3711 size_t i = 2;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3712 while (i < path.length && !isDirSeparator(path[i])) ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3713 if (i == path.length || !isValidFilename(path[2 .. i]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3714 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3715 ++i; // Skip a single dir separator
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3716 size_t j = i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3717 while (j < path.length && !isDirSeparator(path[j])) ++j;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3718 if (!isValidFilename(path[i .. j])) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3719 remainder = path[j .. $];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3720 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3721 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3722 else if (isDriveSeparator(path[1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3723 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3724 import std.ascii : isAlpha;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3725 if (!isAlpha(path[0])) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3726 remainder = path[2 .. $];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3727 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3728 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3729 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3730 remainder = path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3731 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3732 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3733 else version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3734 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3735 remainder = path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3736 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3737 else static assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3738 remainder = ltrimDirSeparators(remainder);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3739
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3740 // Check that each component satisfies isValidComponent.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3741 while (!remainder.empty)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3742 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3743 size_t i = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3744 while (i < remainder.length && !isDirSeparator(remainder[i])) ++i;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3745 assert(i > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3746 if (!isValidComponent(remainder[0 .. i])) return false;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3747 remainder = ltrimDirSeparators(remainder[i .. $]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3748 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3749
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3750 // All criteria passed
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3751 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3752 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3753
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3754 ///
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3755 @safe pure @nogc nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3756 unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3757 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3758 assert(isValidPath("/foo/bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3759 assert(!isValidPath("/foo\0/bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3760 assert(isValidPath("/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3761 assert(isValidPath("a"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3762
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3763 version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3764 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3765 assert(isValidPath(`c:\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3766 assert(isValidPath(`c:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3767 assert(isValidPath(`c:\foo\.\bar\\\..\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3768 assert(!isValidPath(`!:\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3769 assert(!isValidPath(`c::\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3770 assert(!isValidPath(`c:\foo?`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3771 assert(!isValidPath(`c:\foo.`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3772
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3773 assert(isValidPath(`\\server\share`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3774 assert(isValidPath(`\\server\share\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3775 assert(isValidPath(`\\server\share\\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3776 assert(!isValidPath(`\\\server\share\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3777 assert(!isValidPath(`\\server\\share\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3778 assert(!isValidPath(`\\ser*er\share\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3779 assert(!isValidPath(`\\server\sha?e\foo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3780 assert(!isValidPath(`\\server\share\|oo`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3781
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3782 assert(isValidPath(`\\?\<>:"?*|/\..\.`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3783 assert(!isValidPath("\\\\?\\foo\0bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3784
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3785 assert(!isValidPath(`\\.\PhysicalDisk1`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3786 assert(!isValidPath(`\\`));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3787 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3788
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3789 import std.utf : byCodeUnit;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3790 assert(isValidPath("/foo/bar".byCodeUnit));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3791 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3792
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3793 bool isValidPath(Range)(auto ref Range path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3794 if (isConvertibleToString!Range)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3795 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3796 return isValidPath!(StringTypeOf!Range)(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3797 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3798
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3799 @safe unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3800 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3801 assert(testAliasedString!isValidPath("/foo/bar"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3802 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3803
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3804 /** Performs tilde expansion in paths on POSIX systems.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3805 On Windows, this function does nothing.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3806
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3807 There are two ways of using tilde expansion in a path. One
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3808 involves using the tilde alone or followed by a path separator. In
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3809 this case, the tilde will be expanded with the value of the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3810 environment variable $(D HOME). The second way is putting
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3811 a username after the tilde (i.e. $(D ~john/Mail)). Here,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3812 the username will be searched for in the user database
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3813 (i.e. $(D /etc/passwd) on Unix systems) and will expand to
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3814 whatever path is stored there. The username is considered the
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3815 string after the tilde ending at the first instance of a path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3816 separator.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3817
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3818 Note that using the $(D ~user) syntax may give different
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3819 values from just $(D ~) if the environment variable doesn't
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3820 match the value stored in the user database.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3821
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3822 When the environment variable version is used, the path won't
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3823 be modified if the environment variable doesn't exist or it
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3824 is empty. When the database version is used, the path won't be
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3825 modified if the user doesn't exist in the database or there is
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3826 not enough memory to perform the query.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3827
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3828 This function performs several memory allocations.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3829
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3830 Params:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3831 inputPath = The path name to expand.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3832
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3833 Returns:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3834 $(D inputPath) with the tilde expanded, or just $(D inputPath)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3835 if it could not be expanded.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3836 For Windows, $(D expandTilde) merely returns its argument $(D inputPath).
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3837
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3838 Example:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3839 -----
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3840 void processFile(string path)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3841 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3842 // Allow calling this function with paths such as ~/foo
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3843 auto fullPath = expandTilde(path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3844 ...
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3845 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3846 -----
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3847 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3848 string expandTilde(string inputPath) nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3849 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3850 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3851 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3852 import core.exception : onOutOfMemoryError;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3853 import core.stdc.errno : errno, ERANGE;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3854 import core.stdc.stdlib : malloc, free, realloc;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3855
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3856 /* Joins a path from a C string to the remainder of path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3857
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3858 The last path separator from c_path is discarded. The result
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3859 is joined to path[char_pos .. length] if char_pos is smaller
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3860 than length, otherwise path is not appended to c_path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3861 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3862 static string combineCPathWithDPath(char* c_path, string path, size_t char_pos) nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3863 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3864 import core.stdc.string : strlen;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3865
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3866 assert(c_path != null);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3867 assert(path.length > 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3868 assert(char_pos >= 0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3869
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3870 // Search end of C string
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3871 size_t end = strlen(c_path);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3872
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3873 // Remove trailing path separator, if any
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3874 if (end && isDirSeparator(c_path[end - 1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3875 end--;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3876
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3877 // (this is the only GC allocation done in expandTilde())
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3878 string cp;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3879 if (char_pos < path.length)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3880 // Append something from path
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3881 cp = cast(string)(c_path[0 .. end] ~ path[char_pos .. $]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3882 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3883 // Create our own copy, as lifetime of c_path is undocumented
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3884 cp = c_path[0 .. end].idup;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3885
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3886 return cp;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3887 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3888
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3889 // Replaces the tilde from path with the environment variable HOME.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3890 static string expandFromEnvironment(string path) nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3891 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3892 import core.stdc.stdlib : getenv;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3893
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3894 assert(path.length >= 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3895 assert(path[0] == '~');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3896
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3897 // Get HOME and use that to replace the tilde.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3898 auto home = getenv("HOME");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3899 if (home == null)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3900 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3901
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3902 return combineCPathWithDPath(home, path, 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3903 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3904
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3905 // Replaces the tilde from path with the path from the user database.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3906 static string expandFromDatabase(string path) nothrow
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3907 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3908 // bionic doesn't really support this, as getpwnam_r
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3909 // isn't provided and getpwnam is basically just a stub
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3910 version (CRuntime_Bionic)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3911 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3912 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3913 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3914 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3915 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3916 import core.sys.posix.pwd : passwd, getpwnam_r;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3917 import std.string : indexOf;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3918
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3919 assert(path.length > 2 || (path.length == 2 && !isDirSeparator(path[1])));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3920 assert(path[0] == '~');
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3921
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3922 // Extract username, searching for path separator.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3923 auto last_char = indexOf(path, dirSeparator[0]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3924
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3925 size_t username_len = (last_char == -1) ? path.length : last_char;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3926 char* username = cast(char*) malloc(username_len * char.sizeof);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3927 if (!username)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3928 onOutOfMemoryError();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3929 scope(exit) free(username);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3930
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3931 if (last_char == -1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3932 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3933 username[0 .. username_len - 1] = path[1 .. $];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3934 last_char = path.length + 1;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3935 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3936 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3937 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3938 username[0 .. username_len - 1] = path[1 .. last_char];
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3939 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3940 username[username_len - 1] = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3941
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3942 assert(last_char > 1);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3943
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3944 // Reserve C memory for the getpwnam_r() function.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3945 version (unittest)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3946 uint extra_memory_size = 2;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3947 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3948 uint extra_memory_size = 5 * 1024;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3949 char* extra_memory;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3950 scope(exit) free(extra_memory);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3951
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3952 passwd result;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3953 while (1)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3954 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3955 extra_memory = cast(char*) realloc(extra_memory, extra_memory_size * char.sizeof);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3956 if (extra_memory == null)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3957 onOutOfMemoryError();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3958
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3959 // Obtain info from database.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3960 passwd *verify;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3961 errno = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3962 if (getpwnam_r(username, &result, extra_memory, extra_memory_size,
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3963 &verify) == 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3964 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3965 // Succeeded if verify points at result
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3966 if (verify == &result)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3967 // username is found
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3968 path = combineCPathWithDPath(result.pw_dir, path, last_char);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3969 break;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3970 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3971
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3972 if (errno != ERANGE &&
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3973 // On BSD and OSX, errno can be left at 0 instead of set to ERANGE
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3974 errno != 0)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3975 onOutOfMemoryError();
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3976
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3977 // extra_memory isn't large enough
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3978 import core.checkedint : mulu;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3979 bool overflow;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3980 extra_memory_size = mulu(extra_memory_size, 2, overflow);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3981 if (overflow) assert(0);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3982 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3983 return path;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3984 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3985 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3986
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3987 // Return early if there is no tilde in path.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3988 if (inputPath.length < 1 || inputPath[0] != '~')
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3989 return inputPath;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3990
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3991 if (inputPath.length == 1 || isDirSeparator(inputPath[1]))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3992 return expandFromEnvironment(inputPath);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3993 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3994 return expandFromDatabase(inputPath);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3995 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3996 else version (Windows)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3997 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3998 // Put here real windows implementation.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
3999 return inputPath;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4000 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4001 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4002 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4003 static assert(0); // Guard. Implement on other platforms.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4004 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4005 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4006
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4007
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4008 version (unittest) import std.process : environment;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4009 @system unittest
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4010 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4011 version (Posix)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4012 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4013 // Retrieve the current home variable.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4014 auto oldHome = environment.get("HOME");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4015
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4016 // Testing when there is no environment variable.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4017 environment.remove("HOME");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4018 assert(expandTilde("~/") == "~/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4019 assert(expandTilde("~") == "~");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4020
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4021 // Testing when an environment variable is set.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4022 environment["HOME"] = "dmd/test";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4023 assert(expandTilde("~/") == "dmd/test/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4024 assert(expandTilde("~") == "dmd/test");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4025
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4026 // The same, but with a variable ending in a slash.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4027 environment["HOME"] = "dmd/test/";
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4028 assert(expandTilde("~/") == "dmd/test/");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4029 assert(expandTilde("~") == "dmd/test");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4030
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4031 // Recover original HOME variable before continuing.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4032 if (oldHome !is null) environment["HOME"] = oldHome;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4033 else environment.remove("HOME");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4034
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4035 // Test user expansion for root, no /root on Android
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4036 version (OSX)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4037 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4038 assert(expandTilde("~root") == "/var/root", expandTilde("~root"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4039 assert(expandTilde("~root/") == "/var/root/", expandTilde("~root/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4040 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4041 else version (Android)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4042 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4043 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4044 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4045 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4046 assert(expandTilde("~root") == "/root", expandTilde("~root"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4047 assert(expandTilde("~root/") == "/root/", expandTilde("~root/"));
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4048 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4049 assert(expandTilde("~Idontexist/hey") == "~Idontexist/hey");
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4050 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4051 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4052
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4053 version (unittest)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4054 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4055 /* Define a mock RandomAccessRange to use for unittesting.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4056 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4057
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4058 struct MockRange(C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4059 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4060 this(C[] array) { this.array = array; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4061 const
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4062 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4063 @property size_t length() { return array.length; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4064 @property bool empty() { return array.length == 0; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4065 @property C front() { return array[0]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4066 @property C back() { return array[$ - 1]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4067 @property size_t opDollar() { return length; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4068 C opIndex(size_t i) { return array[i]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4069 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4070 void popFront() { array = array[1 .. $]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4071 void popBack() { array = array[0 .. $-1]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4072 MockRange!C opSlice( size_t lwr, size_t upr) const
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4073 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4074 return MockRange!C(array[lwr .. upr]);
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4075 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4076 @property MockRange save() { return this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4077 private:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4078 C[] array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4079 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4080
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4081 static assert( isRandomAccessRange!(MockRange!(const(char))) );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4082 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4083
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4084 version (unittest)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4085 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4086 /* Define a mock BidirectionalRange to use for unittesting.
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4087 */
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4088
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4089 struct MockBiRange(C)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4090 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4091 this(const(C)[] array) { this.array = array; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4092 const
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4093 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4094 @property bool empty() { return array.length == 0; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4095 @property C front() { return array[0]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4096 @property C back() { return array[$ - 1]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4097 @property size_t opDollar() { return array.length; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4098 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4099 void popFront() { array = array[1 .. $]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4100 void popBack() { array = array[0 .. $-1]; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4101 @property MockBiRange save() { return this; }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4102 private:
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4103 const(C)[] array;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4104 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4105
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4106 static assert( isBidirectionalRange!(MockBiRange!(const(char))) );
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4107 }
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4108
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4109 private template BaseOf(R)
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4110 {
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4111 static if (isRandomAccessRange!R && isSomeChar!(ElementType!R))
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4112 alias BaseOf = R;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4113 else
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4114 alias BaseOf = StringTypeOf!R;
1830386684a0 gcc-9.2.0
anatofuz
parents:
diff changeset
4115 }