root/branches/tango/hcf/path.d

Revision 796, 7.4 kB (checked in by Gregor, 1 year ago)

MERGE: trunk r795

Line 
1 /**
2  * Helpful path functions
3  *
4  * Authors:
5  *  Gregor Richards
6  *
7  * License:
8  *  Copyright (c) 2006  Gregor Richards
9  * 
10  *  Permission is hereby granted, free of charge, to any person obtaining a
11  *  copy of this software and associated documentation files (the "Software"),
12  *  to deal in the Software without restriction, including without limitation
13  *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  *  and/or sell copies of the Software, and to permit persons to whom the
15  *  Software is furnished to do so, subject to the following conditions:
16  * 
17  *  The above copyright notice and this permission notice shall be included in
18  *  all copies or substantial portions of the Software.
19  * 
20  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  *  DEALINGS IN THE SOFTWARE.
27  */
28
29 module hcf.path;
30
31 import tango.io.FileConst;
32 import tango.io.FilePath;
33 import tango.io.FileSystem;
34
35 import tango.text.String;
36 import tango.text.Util;
37
38 import tango.stdc.stdlib;
39 import tango.stdc.stringz;
40
41 version (Posix) {
42     import tango.stdc.posix.sys.stat;
43 }
44
45 version (Windows) {
46     import bcd.windows.windows;
47 }
48
49 /* Simple getDirName, etc */
50 char[] getDirName(char[] fname)
51 {
52     return (new FilePath(fname)).path();
53 }
54 char[] getBaseName(char[] fname)
55 {
56     return (new FilePath(fname)).file();
57 }
58 char[] getName(char[] fname)
59 {
60     return (new FilePath(fname)).name();
61 }
62 char[] getExt(char[] fname)
63 {
64     return (new FilePath(fname)).ext();
65 }
66
67 /** Get the system PATH */
68 char[][] getPath()
69 {
70     return split(fromUtf8z(getenv("PATH")), FileConst.SystemPathChar~"");
71 }
72
73 /** From args[0], figure out our path.  Returns 'false' on failure */
74 bool whereAmI(char[] argvz, inout char[] dir, inout char[] bname)
75 {
76     // split it
77     bname = getBaseName(argvz);
78     dir = getDirName(argvz);
79    
80     // on Windows, this is a .exe
81     version (Windows) {
82         bname = defaultExt(bname, "exe");
83     }
84    
85     // is this a directory?
86     if (dir != "") {
87         if (!(new FilePath(dir)).isAbsolute()) {
88             // make it absolute
89             dir = FileSystem.getDirectory() ~ FileConst.PathSeparatorChar ~ dir;
90         }
91         return true;
92     }
93    
94     version (Windows) {
95         // is it in cwd?
96         char[] cwd = FileSystem.getDirectory();
97         if ((new FilePath(cwd ~ FileConst.PathSeparatorChar ~ bname)).exists()) {
98             dir = cwd;
99             return true;
100         }
101     }
102    
103     // rifle through the path
104     char[][] path = getPath();
105     foreach (pe; path) {
106         char[] fullname = pe ~ FileConst.PathSeparatorChar ~ bname;
107         if ((new FilePath(fullname)).exists()) {
108             //version (Windows) {
109                 dir = pe;
110                 return true;
111             /*} else {
112                 stat_t stats;
113                 stat(toUtf8z(fullname), &stats);
114                 if ((cast(int) stats) & 0100) {
115                     dir = pe;
116                     return true;
117                 }
118             }*/
119         }
120     }
121    
122     // bad
123     return false;
124 }
125
126 /// Return a canonical pathname
127 char[] canonPath(char[] origpath)
128 {
129     char[] ret;
130    
131     version (Windows) {
132         // replace any altsep with sep
133         if (altsep.length) {
134             ret = replace(origpath, altsep, sep);
135         } else {
136             ret = origpath.dup;
137         }
138     } else {
139         ret = origpath.dup;
140     }
141    
142     // expand tildes
143     // ret = expandTilde(ret); FIXME
144    
145     // get rid of any duplicate separators
146     for (int i = 0; i < ret.length; i++) {
147         if (ret[i .. (i + 1)] == FileConst.PathSeparatorChar~"") {
148             // drop the duplicate separator
149             i++;
150             while (i < ret.length &&
151                    ret[i .. (i + 1)] == FileConst.PathSeparatorChar~"") {
152                 ret = ret[0 .. i] ~ ret[(i + 1) .. $];
153             }
154         }
155     }
156    
157     // make sure we don't miss a .. element
158     if (ret.length > 3 && ret[($-3) .. $] == FileConst.PathSeparatorChar ~ "..") {
159         ret ~= FileConst.PathSeparatorChar;
160     }
161    
162     // or a . element
163     if (ret.length > 2 && ret[($-2) .. $] == FileConst.PathSeparatorChar ~ ".") {
164         ret ~= FileConst.PathSeparatorChar;
165     }
166    
167     // search for .. elements
168     for (int i = 0; ret.length > 4 && i <= ret.length - 4; i++) {
169         if (ret[i .. (i + 4)] == FileConst.PathSeparatorChar ~ ".." ~ FileConst.PathSeparatorChar) {
170             // drop the previous path element
171             int j;
172             for (j = i - 1; j > 0 && ret[j..(j+1)] != FileConst.PathSeparatorChar~""; j--) {}
173             if (j > 0) {
174                 // cut
175                 ret = ret[0..j] ~ ret[(i + 3) .. $];
176             } else {
177                 // sort of ridiculous, but cut as best we can
178                 ret = FileConst.PathSeparatorChar ~ ret[(i + 3) .. $];
179             }
180             i = j - 1;
181         }
182     }
183    
184     // search for . elements
185     for (int i = 0; ret.length > 2 && i <= ret.length - 3; i++) {
186         if (ret[i .. (i + 3)] == FileConst.PathSeparatorChar ~ "." ~ FileConst.PathSeparatorChar) {
187             // drop this path element
188             ret = ret[0..i] ~ ret[(i + 2) .. $];
189             i--;
190         }
191     }
192
193     // get rid of any introductory ./'s
194     while (ret.length > 2 && ret[0..2] == "." ~ FileConst.PathSeparatorChar) {
195         ret = ret[2..$];
196     }
197    
198     // finally, get rid of any trailing separators
199     while (ret.length &&
200            ret[($ - 1) .. $] == FileConst.PathSeparatorChar~"") {
201         ret = ret[0 .. ($ - 1)];
202     }
203    
204     return ret;
205 }
206
207 /** Make a directory and all parent directories */
208 void mkdirP(char[] dir)
209 {
210     dir = canonPath(dir);
211     version (Windows) {
212         dir = std.string.replace(dir, "/", "\\");
213     }
214    
215     // split it into elements
216     char[][] dires = split(dir, FileConst.PathSeparatorChar~"");
217    
218     char[] curdir;
219    
220     // check for root dir
221     if (dires.length &&
222         dires[0] == "") {
223         curdir = FileConst.PathSeparatorChar~"";
224         dires = dires[1..$];
225     }
226    
227     // then go piece-by-piece, making directories
228     foreach (dire; dires) {
229         if (curdir.length) {
230             curdir ~= FileConst.PathSeparatorChar ~ dire;
231         } else {
232             curdir ~= dire;
233         }
234        
235         if (!(new FilePath(curdir)).exists()) {
236             (new FilePath(curdir)).createFolder();
237         }
238     }
239 }
240
241 /** Remove a file or directory and all of its children */
242 void rmRecursive(char[] name)
243 {
244     // can only delete writable files on Windows
245     version (Windows) {
246         SetFileAttributesA(toUtf8z(name),
247                            GetFileAttributesA(toUtf8z(name)) &
248                            ~FILE_ATTRIBUTE_READONLY);
249     }
250    
251     if ((new FilePath(name)).isFolder()) {
252         foreach (elem; (new FilePath(name)).toList((FilePath path, bool isFolder) { return true; })) {
253             // don't delete . or ..
254             if (elem.name == "." ||
255                 elem.name == "..") continue;
256             rmRecursive(name ~ FileConst.PathSeparatorChar ~ elem.name);
257         }
258        
259         // remove the directory itself
260         (new FilePath(name)).remove();
261     } else {
262         (new FilePath(name)).remove();
263     }
264 }
Note: See TracBrowser for help on using the browser.