1
2
3
4
5
6 using System;
7 using System.Collections;
8
9 namespace System.IO
10 {
11 public class InvalidPathException : Exception
12 {
13 public nothrow InvalidPathException(const string& message_) : base(message_)
14 {
15 }
16 }
17
18 public string GetFullPath(const string& path)
19 {
20 string cp = Path.MakeCanonical(path);
21 string p = cp;
22 if (Path.IsRelative(cp))
23 {
24 p.Clear();
25 p.Append(GetCurrentWorkingDirectory());
26 p.Append('/');
27 p.Append(cp);
28 }
29 List<string> components = p.Split('/');
30 long w = 0;
31 long n = components.Count();
32 for (long i = 0; i < n; ++i;)
33 {
34 string c = components[i];
35 if (i == 0 || (!c.IsEmpty() && c != "."))
36 {
37 if (c == "..")
38 {
39 --w;
40 if (w < 0)
41 {
42 throw InvalidPathException("path '" + path + "' is invalid");
43 }
44 }
45 else
46 {
47 if (w != i)
48 {
49 components[w] = components[i];
50 }
51 ++w;
52 }
53 }
54 }
55 if (w == 0)
56 {
57 return "/";
58 }
59 string result;
60 for (long i = 0; i < w; ++i;)
61 {
62 if (i != 0)
63 {
64 result.Append('/');
65 }
66 result.Append(components[i]);
67 }
68 if (result.IsEmpty())
69 {
70 return "/";
71 }
72 else
73 {
74 return result;
75 }
76 }
77
78 public static class Path
79 {
80 public static bool Exists(const string& path)
81 {
82 byte[statBufSize] statBuf;
83 int result = stat(path.Chars(), &statBuf[0], statBufSize);
84 return result != -1;
85 }
86 public static nothrow string MakeCanonical(const string& path)
87 {
88 string result;
89 char prev = ' ';
90 for (char c : path)
91 {
92 if (c == '/')
93 {
94 if (prev != '/')
95 {
96 result.Append(c);
97 }
98 }
99 else
100 {
101 result.Append(c);
102 }
103 prev = c;
104 }
105 if (result == "/")
106 {
107 return result;
108 }
109 if (!result.IsEmpty())
110 {
111 if (result[result.Length() - 1] == '/')
112 {
113 return result.Substring(0, result.Length() - 1);
114 }
115 }
116 return result;
117 }
118 public static nothrow string ChangeExtension(const string& path, const string& extension)
119 {
120 long lastDotPos = path.RFind('.');
121 long lastSlashPos = path.RFind('/');
122 if (lastSlashPos != -1 && lastDotPos < lastSlashPos)
123 {
124 lastDotPos = -1;
125 }
126 if (extension.IsEmpty())
127 {
128 if (lastDotPos != -1)
129 {
130 return path.Substring(0, lastDotPos);
131 }
132 else
133 {
134 return path;
135 }
136 }
137 else
138 {
139 if (lastDotPos == -1)
140 {
141 if (extension[0] == '.')
142 {
143 return path + extension;
144 }
145 else
146 {
147 return path + "." + extension;
148 }
149 }
150 else
151 {
152 if (extension[0] == '.')
153 {
154 return path.Substring(0, lastDotPos) + extension;
155 }
156 else
157 {
158 return path.Substring(0, lastDotPos + 1) + extension;
159 }
160 }
161 }
162 }
163 public static nothrow bool HasExtension(const string& path)
164 {
165 string p = MakeCanonical(path);
166 long lastDotPos = p.RFind('.');
167 if (lastDotPos != -1)
168 {
169 long lastDirSep = p.Find('/', lastDotPos + 1);
170 if (lastDirSep > lastDotPos)
171 {
172 return false;
173 }
174 else if (lastDotPos < p.Length() - 1)
175 {
176 return true;
177 }
178 else
179 {
180 return false;
181 }
182 }
183 else
184 {
185 return false;
186 }
187 }
188 public static nothrow string GetExtension(const string& path)
189 {
190 string p = MakeCanonical(path);
191 long lastDotPos = p.RFind('.');
192 if (lastDotPos != -1)
193 {
194 if (p.Find('/', lastDotPos + 1) != -1)
195 {
196 return string();
197 }
198 else
199 {
200 return p.Substring(lastDotPos);
201 }
202 }
203 else
204 {
205 return string();
206 }
207 }
208 public static nothrow string GetFileName(const string& path)
209 {
210 if (path.IsEmpty())
211 {
212 return string();
213 }
214 else
215 {
216 string p = MakeCanonical(path);
217 char lastChar = p[p.Length() - 1];
218 if (lastChar == '/')
219 {
220 return string();
221 }
222 else
223 {
224 long lastDirSepPos = p.RFind('/');
225 if (lastDirSepPos != -1)
226 {
227 return p.Substring(lastDirSepPos + 1);
228 }
229 else
230 {
231 return p;
232 }
233 }
234 }
235 }
236 public static nothrow string GetFileNameWithoutExtension(const string& path)
237 {
238 string fileName = GetFileName(path);
239 long lastDotPos = fileName.RFind('.');
240 if (lastDotPos != -1)
241 {
242 return fileName.Substring(0, lastDotPos);
243 }
244 else
245 {
246 return fileName;
247 }
248 }
249 public static nothrow string GetDirectoryName(const string& path)
250 {
251 string p = MakeCanonical(path);
252 if (p.IsEmpty())
253 {
254 return string();
255 }
256 else
257 {
258 long lastDirSepPos = p.RFind('/');
259 if (lastDirSepPos != -1)
260 {
261 return p.Substring(0, lastDirSepPos);
262 }
263 else
264 {
265 return string();
266 }
267 }
268 }
269 public static nothrow string Combine(const string& path1, const string& path2)
270 {
271 string p1 = MakeCanonical(path1);
272 string p2 = MakeCanonical(path2);
273 if (p1.IsEmpty())
274 {
275 return p2;
276 }
277 else if (p2.IsEmpty())
278 {
279 return p1;
280 }
281 else
282 {
283 if (IsAbsolute(p2))
284 {
285 return p2;
286 }
287 else
288 {
289 string result = p1;
290 if (p1[p1.Length() - 1] != '/')
291 {
292 result.Append('/');
293 }
294 result.Append(p2);
295 return result;
296 }
297 }
298 }
299 public static nothrow bool IsAbsolute(const string& path)
300 {
301 if (path.IsEmpty())
302 {
303 return false;
304 }
305 else
306 {
307 string p = MakeCanonical(path);
308 if (p[0] == '/')
309 {
310 return true;
311 }
312 else
313 {
314 return false;
315 }
316 }
317 }
318 public static nothrow bool IsRelative(const string& path)
319 {
320 return !IsAbsolute(path);
321 }
322 public static string GetParent(const string& path)
323 {
324 string fullPath = GetFullPath(path);
325 long lastSlashPos = fullPath.RFind('/');
326 if (lastSlashPos == -1)
327 {
328 return string();
329 }
330 else
331 {
332 return fullPath.Substring(0, lastSlashPos);
333 }
334 }
335 }
336 }