cmake build system: visiblity support for clang
[supercollider.git] / SCClassLibrary / Common / Files / PathName.sc
blobe01e8db7a5c6cfcd7192f3dd1d840dd8f1550d77
1 PathName {
3         var <fullPath, colonIndices;
5         classvar <>scroot;
6         classvar <>secondVolume; //needed only for OS9 path conversions
7         classvar <>tmp;
9         *new { arg path = "";
10                 ^super.new.init(path.standardizePath);
11         }
12         *fromOS9 { arg path="";
13                 if(secondVolume.notNil and:
14                         { path.copyRange(0,secondVolume.size - 1) == secondVolume },{
15                                 path = "/Volumes/" ++ path;
16                 });
17                 ^super.new.init(
18                         String.streamContents({ arg s;
19                                 path.do({ arg char,i;
20                                         if(char == $:,{
21                                                 if(i != 0,{ // leading : is not wanted in unix
22                                                         s << $/
23                                                 })
24                                         },{
25                                                 s <<  char
26                                         });
27                                 })
28                         })
29                 )
30         }
31         *initClass {
32                 scroot = File.getcwd;
33                 tmp = Platform.defaultTempDir;
34                 tmp.isNil.if(
35                         {"No valid temp directory found. Please set this manually using PathName.tmp_".warn});
36         }
37         init { arg inPath;
38                 fullPath = inPath;
39         }
40         colonIndices {
41                 ^colonIndices ?? {
42                         colonIndices = List.new;
43                         fullPath.do({ arg eachChar, i;
44                                 if (eachChar.isPathSeparator, { colonIndices.add(i) });
45                         });
46                         colonIndices
47                 }
48         }
49         fileName {
50                 ^fullPath.copyRange((this.lastColonIndex) + 1, (fullPath.size -1).max(0));
51         }
53         fileNameWithoutExtension {
54                 var fileName;
55                 fileName = this.fileName;
56                 fileName.reverseDo({ arg char,i;
57                         if(char == $.,{
58                                 ^fileName.copyRange(0,fileName.size - (i + 2))
59                         })
60                 });
61                 ^fileName
62         }
64         fileNameWithoutDoubleExtension {
65                 var fileName, pathName;
66                 fileName = this.fileNameWithoutExtension;
67                 pathName = PathName( fileName );
68                 ^pathName.fileNameWithoutExtension;
69         }
71         extension {
72                 var fileName;
73                 fileName = this.fileName;
74                 fileName.reverseDo({ arg char,i;
75                         if(char == $.,{
76                                 ^fileName.copyRange(fileName.size - i,fileName.size - 1)
77                         })
78                 });
79                 ^""
80         }
81         pathOnly {
82                 ^fullPath.copyRange(0, this.lastColonIndex);
83         }
85         diskName {  ^fullPath.copyRange(0, this.colonIndices.first - 1) }
87         isRelativePath { ^this.isAbsolutePath.not }
89         isAbsolutePath {
90                 ^fullPath.at(0).isPathSeparator
91         }
93         absolutePath{
94                 ^fullPath.absolutePath;
95         }
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;
103                 a = mePath.split(r);
104                 b = relativeTo.split(r);
106                 i=0;
107                 while{a[i]==b[i] and:{i<a.size}}{
108                         i = i + 1;
109                 };
110                 ^(".."++r).dup(b.size-i).join ++ a[i..].join(r)
111         }
112         asAbsolutePath {
113                 if(this.isAbsolutePath,{
114                         ^fullPath
115                 },{
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
120                 })
121         }
122         allFolders {
123                 var folderNames, pathCopy;
124                 folderNames = List.new;
125                 pathCopy = fullPath;
127                 this.colonIndices.doAdjacentPairs({ arg startColon, endColon;
128                         folderNames.add( fullPath.copyRange(startColon + 1, endColon - 1) );
129                 });
131                 ^folderNames
132         }
134         folderName {
135                 var indexBeforeFolder,ci;
136                 ci = this.colonIndices;
137                 if (ci.isEmpty, { ^"" });
139                 indexBeforeFolder =
140                 if (ci.size == 1, 0,
141                         { ci.at(ci.size - 2) + 1 });
143                 ^fullPath.copyRange(indexBeforeFolder, this.lastColonIndex - 1);
144         }
146         lastColonIndex {
147                 var ci;
148                 ci = this.colonIndices;
149                 ^if (ci.isEmpty, { -1 }, { ci.last }) ;
150         }
152         nextName {
153                 var nextName;
154                 nextName = if (fullPath.last.isDecDigit,
155                         { this.noEndNumbers ++ (this.endNumber + 1).asString;
156                         },
157                         {fullPath ++ "1"; }
158                 );
159                 ^nextName;
160         }
162         noEndNumbers {
163                 var result, count = 0, char;
165                 result = fullPath.copy;
166                 while(
167                         {       count = count + 1;
168                                 char = fullPath.at(fullPath.size - count);
169                                 char.notNil and: { char.isDecDigit};
170                         },
171                         { result = result.copyRange(0,  result.size - 2) }
172                         );
173                 ^result;
174         }
176         endNumber {     // turn consecutive digits at the end of fullPath into a number.
178                 var reverseNumString = "";
179                 var count = 0, char, number;
181                 while(
182                         {       count = count + 1;
183                                 char = fullPath.at(fullPath.size - count);
184                                 char.notNil and: { char.isDecDigit};
185                         },
186                         { reverseNumString = reverseNumString ++ char }
187                         );
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))
192                         }
193                 );
194                 ^number
195         }
197         /* concatenation */
198         +/+ { | path |
199                 var otherFullPath = path.respondsTo(\fullPath).if({ path.fullPath }, { path.asString });
200                 ^this.class.new(fullPath +/+ otherFullPath)
201         }
203         /* additional methods jrh */
205         entries {
206                 var path;
207                 path = fullPath;
208                 if(path.last.isPathSeparator.not, { path = path ++ thisProcess.platform.pathSeparator });
209                 ^pathMatch(path ++ "*").collect({ arg item; PathName(item) });
210         }
212         pathMatch {
213                 ^pathMatch(fullPath)
214         }
216         isFolder {
217                 var path;
218                 path = this.pathMatch;
219                 ^if(path.notEmpty, {
220                         path.at(0).last.isPathSeparator
221                 }, { false });
222         }
223         isFile {
224                 var path;
225                 path = this.pathMatch;
226                 ^if(path.notEmpty, {
227                         path.at(0).last.isPathSeparator.not
228                 }, { false });
229         }
231         files {
232                 ^this.entries.select({ arg item; item.isFile })
233         }
234         folders {
235                 ^this.entries.select({ arg item; item.isFolder })
236         }
237         deepFiles {
238                 ^this.entries.collect({ arg item;
239                         if(item.isFile,{
240                                 item
241                         },{
242                                 item.deepFiles
243                         })
244                 }).flat
245         }
247         parentPath {
248                 var ci = this.colonIndices;
250                 ^if((fullPath.last.isPathSeparator) && (ci.size > 1), {
251                         fullPath.copyRange(0, ci[ci.size - 2]);
252                 }, {
253                         fullPath.copyRange(0, this.lastColonIndex)
254                 });
255         }
257         foldersWithoutCVS { arg path;
258                 ^this.folders(path).reject({ arg item; item.isCVS })
259         }
260         isCVS {
261                 ^this.fileName == "CVS";
262         }
263         foldersWithoutSVN { arg path;
264                 ^this.folders(path).reject({ arg item; item.isSVN })
265         }
266         isSVN {
267                 ^this.fileName == ".svn";
268         }
269         filesDo { arg func;
270                 this.files.do(func);
271                 this.foldersWithoutSVN.do { arg pathname;
272                         pathname.filesDo(func)
273                 }
274         }
275         filesDoNoCVS { arg func;
276                 this.files.do(func);
277                 this.foldersWithoutCVS.do { arg pathname;
278                         pathname.filesDo(func)
279                 }
280         }
282         filesDoNoSVN { arg func;
283                 this.files.do(func);
284                 this.foldersWithoutSVN.do { arg pathname;
285                         pathname.filesDo(func)
286                 }
287         }
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) }
295                         .do(func);
296                 this.folders.reject{|afolder| ignoreFolders.includes(afolder.folderName.asSymbol) }
297                         .do{ arg pathname;
298                                 pathname.helpFilesDo(func)
299                         }
300         }
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
306                 });
307                 this.foldersWithoutSVN.do({ arg item;
308                         item.streamTree(str, tabs + 1);
309                 });
310         }
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
316                 });
317                 this.foldersWithoutCVS.do({ arg item;
318                         item.streamTree(str, tabs + 1);
319                 });
320         }
322         dumpTree {
323                 this.streamTree(Post)
324         }
326         printOn { arg stream;
327                 stream << "PathName(" << fullPath <<")"
328         }
330         dumpToDoc { arg title="Untitled";
331                 var str, doc;
332                 doc = Document.new(title);
333                 str = CollStream.new;
334                 this.streamTree(str);
335                 doc.string = str.collection;
336                 ^doc
337         }