3 var <fullPath, colonIndices;
6 classvar <>secondVolume; //needed only for OS9 path conversions
10 ^super.new.init(path.standardizePath);
12 *fromOS9 { arg path="";
13 if(secondVolume.notNil and:
14 { path.copyRange(0,secondVolume.size - 1) == secondVolume },{
15 path = "/Volumes/" ++ path;
18 String.streamContents({ arg s;
21 if(i != 0,{ // leading : is not wanted in unix
33 tmp = Platform.defaultTempDir;
35 {"No valid temp directory found. Please set this manually using PathName.tmp_".warn});
42 colonIndices = List.new;
43 fullPath.do({ arg eachChar, i;
44 if (eachChar.isPathSeparator, { colonIndices.add(i) });
50 ^fullPath.copyRange((this.lastColonIndex) + 1, (fullPath.size -1).max(0));
53 fileNameWithoutExtension {
55 fileName = this.fileName;
56 fileName.reverseDo({ arg char,i;
58 ^fileName.copyRange(0,fileName.size - (i + 2))
64 fileNameWithoutDoubleExtension {
65 var fileName, pathName;
66 fileName = this.fileNameWithoutExtension;
67 pathName = PathName( fileName );
68 ^pathName.fileNameWithoutExtension;
73 fileName = this.fileName;
74 fileName.reverseDo({ arg char,i;
76 ^fileName.copyRange(fileName.size - i,fileName.size - 1)
82 ^fullPath.copyRange(0, this.lastColonIndex);
85 diskName { ^fullPath.copyRange(0, this.colonIndices.first - 1) }
87 isRelativePath { ^this.isAbsolutePath.not }
90 ^fullPath.at(0).isPathSeparator
94 ^fullPath.absolutePath;
97 asRelativePath { |relativeTo|
98 var r, a, b, i, mePath;
99 mePath = this.fullPath.absolutePath;
100 relativeTo = (relativeTo ? scroot ).absolutePath;
101 r = thisProcess.platform.pathSeparator;
104 b = relativeTo.split(r);
107 while{a[i]==b[i] and:{i<a.size}}{
110 ^(".."++r).dup(b.size-i).join ++ a[i..].join(r)
113 if(this.isAbsolutePath,{
116 // this assumes relative to the sc app
117 // deprecated b/c String:absolutePath uses File.getcwd, more robust
118 // ^scroot ++ "/" ++ fullPath;
119 ^fullPath.absolutePath
123 var folderNames, pathCopy;
124 folderNames = List.new;
127 this.colonIndices.doAdjacentPairs({ arg startColon, endColon;
128 folderNames.add( fullPath.copyRange(startColon + 1, endColon - 1) );
135 var indexBeforeFolder,ci;
136 ci = this.colonIndices;
137 if (ci.isEmpty, { ^"" });
141 { ci.at(ci.size - 2) + 1 });
143 ^fullPath.copyRange(indexBeforeFolder, this.lastColonIndex - 1);
148 ci = this.colonIndices;
149 ^if (ci.isEmpty, { -1 }, { ci.last }) ;
154 nextName = if (fullPath.last.isDecDigit,
155 { this.noEndNumbers ++ (this.endNumber + 1).asString;
163 var result, count = 0, char;
165 result = fullPath.copy;
168 char = fullPath.at(fullPath.size - count);
169 char.notNil and: { char.isDecDigit};
171 { result = result.copyRange(0, result.size - 2) }
176 endNumber { // turn consecutive digits at the end of fullPath into a number.
178 var reverseNumString = "";
179 var count = 0, char, number;
183 char = fullPath.at(fullPath.size - count);
184 char.notNil and: { char.isDecDigit};
186 { reverseNumString = reverseNumString ++ char }
189 // convert reverseNumString back to number (digits times powers of 10)
190 number = reverseNumString.inject(0,
191 { arg sum, eachChar, i; sum = sum + (eachChar.digit * (10 ** i))
199 var otherFullPath = path.respondsTo(\fullPath).if({ path.fullPath }, { path.asString });
200 ^this.class.new(fullPath +/+ otherFullPath)
203 /* additional methods jrh */
208 if(path.last.isPathSeparator.not, { path = path ++ thisProcess.platform.pathSeparator });
209 ^pathMatch(path ++ "*").collect({ arg item; PathName(item) });
218 path = this.pathMatch;
220 path.at(0).last.isPathSeparator
225 path = this.pathMatch;
227 path.at(0).last.isPathSeparator.not
232 ^this.entries.select({ arg item; item.isFile })
235 ^this.entries.select({ arg item; item.isFolder })
238 ^this.entries.collect({ arg item;
248 var ci = this.colonIndices;
250 ^if((fullPath.last.isPathSeparator) && (ci.size > 1), {
251 fullPath.copyRange(0, ci[ci.size - 2]);
253 fullPath.copyRange(0, this.lastColonIndex)
257 foldersWithoutCVS { arg path;
258 ^this.folders(path).reject({ arg item; item.isCVS })
261 ^this.fileName == "CVS";
263 foldersWithoutSVN { arg path;
264 ^this.folders(path).reject({ arg item; item.isSVN })
267 ^this.fileName == ".svn";
271 this.foldersWithoutSVN.do { arg pathname;
272 pathname.filesDo(func)
275 filesDoNoCVS { arg func;
277 this.foldersWithoutCVS.do { arg pathname;
278 pathname.filesDo(func)
282 filesDoNoSVN { arg func;
284 this.foldersWithoutSVN.do { arg pathname;
285 pathname.filesDo(func)
289 // Iterates over all files within this path which match criteria for being help files.
290 // Doesn't iterate over the help files listed in the Help tree - see Help:do for that.
291 helpFilesDo { arg func;
292 var extensions = #['html', 'htm', 'scd', 'rtf', 'rtfd']; // included
293 var ignoreFolders = #['ignore', '.svn', '_darcs', 'CVS', '.git']; // excluded
294 this.files.select{|afile| extensions.includes(afile.extension.asSymbol) }
296 this.folders.reject{|afolder| ignoreFolders.includes(afolder.folderName.asSymbol) }
298 pathname.helpFilesDo(func)
301 streamTree { arg str, tabs=0;
302 str << this.fullPath << Char.nl;
303 this.files.do({ arg item;
304 tabs.do({ str << Char.tab });
305 str << item.fileNameWithoutExtension << Char.nl
307 this.foldersWithoutSVN.do({ arg item;
308 item.streamTree(str, tabs + 1);
311 streamTreeNoCVS { arg str, tabs=0;
312 str << this.fullPath << Char.nl;
313 this.files.do({ arg item;
314 tabs.do({ str << Char.tab });
315 str << item.fileNameWithoutExtension << Char.nl
317 this.foldersWithoutCVS.do({ arg item;
318 item.streamTree(str, tabs + 1);
323 this.streamTree(Post)
326 printOn { arg stream;
327 stream << "PathName(" << fullPath <<")"
330 dumpToDoc { arg title="Untitled";
332 doc = Document.new(title);
333 str = CollStream.new;
334 this.streamTree(str);
335 doc.string = str.collection;