root/branches/bud/hcf/path.d

Revision 196, 5.9 kB (checked in by Gregor, 2 years ago)

hcf/path.d: Allow tildes in Unix paths.

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 public import std.path;
32
33 import std.stdio;
34 import std.file;
35 import std.string;
36
37 import std.c.stdlib;
38
39 version (Windows) {
40     import bcd.windows.windows;
41 }
42
43 /** Get the system PATH */
44 char[][] getPath()
45 {
46     return split(toString(getenv("PATH")), std.path.pathsep);
47 }
48
49 /** From args[0], figure out our path.  Returns 'false' on failure */
50 bool whereAmI(char[] argvz, inout char[] dir, inout char[] bname)
51 {
52     // split it
53     bname = getBaseName(argvz);
54     dir = getDirName(argvz);
55    
56     // on Windows, this is a .exe
57     version (Windows) {
58         bname = defaultExt(bname, "exe");
59     }
60    
61     // is this a directory?
62     if (dir != "") {
63         if (!std.path.isabs(dir)) {
64             // make it absolute
65             dir = getcwd() ~ std.path.sep ~ dir;
66         }
67         return true;
68     }
69    
70     version (Windows) {
71         // is it in cwd?
72         char[] cwd = getcwd();
73         if (exists(cwd ~ std.path.sep ~ bname)) {
74             dir = cwd;
75             return true;
76         }
77     }
78    
79     // rifle through the path
80     char[][] path = getPath();
81     foreach (pe; path) {
82         char[] fullname = pe ~ std.path.sep ~ bname;
83         if (exists(fullname)) {
84             version (Windows) {
85                 dir = pe;
86                 return true;
87             } else {
88                 if (getAttributes(fullname) & 0100) {
89                     dir = pe;
90                     return true;
91                 }
92             }
93         }
94     }
95    
96     // bad
97     return false;
98 }
99
100 /// Return a canonical pathname
101 char[] canonPath(char[] origpath)
102 {
103     char[] ret;
104    
105     // replace any altsep with sep
106     if (altsep.length) {
107         ret = replace(origpath, altsep, sep);
108     } else {
109         ret = origpath.dup;
110     }
111    
112     // expand tildes
113     ret = expandTilde(ret);
114    
115     // get rid of any duplicate separators
116     for (int i = 0; i < ret.length; i++) {
117         if (ret[i .. (i + 1)] == sep) {
118             // drop the duplicate separator
119             i++;
120             while (i < ret.length &&
121                    ret[i .. (i + 1)] == sep) {
122                 ret = ret[0 .. i] ~ ret[(i + 1) .. $];
123             }
124         }
125     }
126    
127     // make sure we don't miss a .. element
128     if (ret.length > 4 && ret[($-3) .. $] == std.path.sep ~ "..") {
129         ret ~= std.path.sep;
130     }
131    
132     // search for .. elements
133     for (int i = 0; ret.length > 4 && i <= ret.length - 4; i++) {
134         if (ret[i .. (i + 4)] == std.path.sep ~ ".." ~ std.path.sep) {
135             // drop the previous path element
136             int j;
137             for (j = i - 1; j > 0 && ret[j..(j+1)] != std.path.sep; j--) {}
138             if (j > 0) {
139                 // cut
140                 ret = ret[0..j] ~ ret[(i + 3) .. $];
141             } else {
142                 // sort of ridiculous, but cut as best we can
143                 ret = std.path.sep ~ ret[(i + 3) .. $];
144             }
145             i = j - 1;
146         }
147     }
148    
149     // search for . elements
150     for (int i = 0; ret.length > 2 && i <= ret.length - 2; i++) {
151         if (ret[i .. (i + 2)] == std.path.sep ~ ".") {
152             // drop this path element
153             ret = ret[0..i] ~ ret[(i + 2) .. $];
154             i--;
155         }
156     }
157    
158     // finally, get rid of any trailing separators
159     while (ret.length &&
160            ret[($ - 1) .. $] == sep) {
161         ret = ret[0 .. ($ - 1)];
162     }
163    
164     return ret;
165 }
166
167 /** Make a directory and all parent directories */
168 void mkdirP(char[] dir)
169 {
170     dir = canonPath(dir);
171     version (Windows) {
172         dir = std.string.replace(dir, "/", "\\");
173     }
174    
175     // split it into elements
176     char[][] dires = split(dir, sep);
177    
178     char[] curdir;
179    
180     // check for root dir
181     if (dires.length &&
182         dires[0] == "") {
183         curdir = std.path.sep;
184         dires = dires[1..$];
185     }
186    
187     // then go piece-by-piece, making directories
188     foreach (dire; dires) {
189         if (curdir.length) {
190             curdir ~= sep ~ dire;
191         } else {
192             curdir ~= dire;
193         }
194        
195         if (!exists(curdir)) {
196             mkdir(curdir);
197         }
198     }
199 }
200
201 /** Remove a file or directory and all of its children */
202 void rmRecursive(char[] name)
203 {
204     // can only delete writable files on Windows
205     version (Windows) {
206         SetFileAttributesA(toStringz(name),
207                            GetFileAttributesA(toStringz(name)) &
208                            ~FILE_ATTRIBUTE_READONLY);
209     }
210    
211     if (isdir(name)) {
212         foreach (elem; listdir(name)) {
213             // don't delete . or ..
214             if (elem == "." ||
215                 elem == "..") continue;
216             rmRecursive(name ~ std.path.sep ~ elem);
217         }
218        
219         // remove the directory itself
220         rmdir(name);
221     } else {
222         std.file.remove(name);
223     }
224 }
Note: See TracBrowser for help on using the browser.