cmake build system: visiblity support for clang
[supercollider.git] / SCClassLibrary / Common / Collections / String.sc
blob59cb82e8c0f68cfc3249c9ab58bdf664c01d2d76
1 String[char] : RawArray {
2         classvar <>unixCmdActions;
4         *initClass {
5                 unixCmdActions = IdentityDictionary.new;
6         }
8         *doUnixCmdAction {
9                 arg res, pid;
10                 unixCmdActions[pid].value(res, pid);
11                 unixCmdActions.removeAt(pid);
12         }
14         prUnixCmd {
15                 arg postOutput = true;
16                 _String_POpen
17                 ^this.primitiveFailed
18         }
20         // runs a unix command and sends stdout to the post window
21         unixCmd {
22                 arg action, postOutput = true;
23                 var pid;
24                 pid = this.prUnixCmd(postOutput);
25                 if(action.notNil) {
26                         unixCmdActions.put(pid, action);
27                 };
28                 ^pid;
29         }
31         // Like unixCmd but gets the result into a string
32         unixCmdGetStdOut {
33                 var pipe, lines, line;
35                 pipe = Pipe.new(this, "r");
36                 lines = "";
37                 line = pipe.getLine;
38                 while({line.notNil}, {lines = lines ++ line ++ "\n"; line = pipe.getLine; });
39                 pipe.close;
41                 ^lines;
42         }
44         asSymbol {
45                 _StringAsSymbol
46                 ^this.primitiveFailed
47         }
48         asInteger {
49                 _String_AsInteger
50                 ^this.primitiveFailed
51         }
52         asFloat {
53                 _String_AsFloat
54                 ^this.primitiveFailed
55         }
56         ascii {
57                 ^Array.fill(this.size, { |i| this[i].ascii })
58         }
60         stripRTF {
61                 _StripRtf
62                 ^this.primitiveFailed
63         }
65         stripHTML {
66                 _StripHtml
67                 ^this.primitiveFailed
68         }
70         getSCDir {
71                 _String_GetResourceDirPath
72                 ^this.primitiveFailed
73         }
75         *scDir {
76                 ^"".getSCDir
77         }
79         compare { arg aString, ignoreCase=false; _StringCompare }
80         < { arg aString; ^this.compare(aString, true) < 0 }
81         > { arg aString; ^this.compare(aString, true) > 0 }
82         <= { arg aString; ^this.compare(aString, true) <= 0 }
83         >= { arg aString; ^this.compare(aString, true) >= 0 }
84         == { arg aString; ^this.compare(aString, true) == 0 }
85         != { arg aString; ^this.compare(aString, true) != 0 }
86         hash { _StringHash }
88         // no sense doing collect as per superclass collection
89         performBinaryOpOnSimpleNumber { arg aSelector, aNumber;
90                 ^aNumber.asString.perform(aSelector, this);
91         }
92         performBinaryOpOnComplex { arg aSelector, aComplex;
93                 ^aComplex.asString.perform(aSelector, this);
94         }
96         isString { ^true }
97         asString { ^this }
98         asCompileString { _String_AsCompileString; }
99         species { ^String }
101         postln { _PostLine }
102         post { _PostString }
103         postcln { "// ".post; this.postln; }
104         postc { "// ".post; this.post; }
106         postf { arg ... items;  ^this.prFormat( items.collect(_.asString) ).post }
107         format { arg ... items; ^this.prFormat( items.collect(_.asString) ) }
108         prFormat { arg items; _String_Format ^this.primitiveFailed }
109         matchRegexp { arg string, start = 0, end; _String_Regexp ^this.primitiveFailed }
111         fformat { arg ... args;
112                 var str, resArgs, val, func;
113                 var suffixes, sig = false;
115                 this.do { |char|
116                         if(sig) {
117                                 val = args.removeAt(0);
118                                 func = Post.formats[char];
119                                 if(func.isNil) {
120                                         resArgs = resArgs.add(val);
121                                         str = str ++ char
122                                 } {
123                                         resArgs = resArgs.add(func.value(val))
124                                 };
125                                 sig = false;
126                         } {
127                                 str = str ++ char
128                         };
129                         if(char == $%) { sig = true };
130                 };
131                 ^str.format(*resArgs)
132         }
134         die { arg ... culprits;
135                 if(culprits.notEmpty,{
136                         ("\n\nFATAL ERROR: ").postln;
137                         culprits.do({ arg c; if(c.isString,{c.postln},{c.dump}) });
138                 });
139                 Error(this).throw;
140         }
141         error { "ERROR:\n".post; this.postln; }
142         warn { "WARNING:\n".post; this.postln }
143         inform { ^this.postln }
144         ++ { arg anObject; ^this prCat: anObject.asString; }
145         + { arg anObject; ^this prCat: " " prCat: anObject.asString; }
146         catArgs { arg ... items; ^this.catList(items) }
147         scatArgs { arg ... items; ^this.scatList(items) }
148         ccatArgs { arg ... items; ^this.ccatList(items) }
149         catList { arg list;
150                 // concatenate this with a list as a string
151                 var string = this.copy;
152                 list.do({ arg item, i;
153                         string = string ++ item;
154                 });
155                 ^string
156         }
157         scatList { arg list;
158                 var string = this.copy;
159                 list.do({ arg item, i;
160                         string = string prCat: " " ++ item;
161                 });
162                 ^string
163         }
164         ccatList { arg list;
165                 var string = this.copy;
166                 list.do({ arg item, i;
167                         string = string prCat: ", " ++ item;
168                 });
169                 ^string
170         }
171         split { arg separator=$/;
172                 var word="";
173                 var array=[];
174                 separator=separator.ascii;
176                 this.do({arg let,i;
177                         if(let.ascii != separator ,{
178                                 word=word++let;
179                         },{
180                                 array=array.add(word);
181                                 word="";
182                         });
183                 });
184                 ^array.add(word);
185         }
187         containsStringAt { arg index, string;
188                 ^compare( this[index..index + string.size-1], string, false) == 0
189         }
191         icontainsStringAt { arg index, string;
192                 ^compare( this[index..index + string.size-1], string, true) == 0
193         }
196         contains { arg string, offset = 0;
197                 ^this.find(string, false, offset).notNil
198         }
199         containsi { arg string, offset = 0;
200                 ^this.find(string, true, offset).notNil
201         }
203         findRegexp { arg regexp, offset = 0;
204        _String_FindRegexp
205        ^this.primitiveFailed
206         }
208         findAllRegexp { arg string, offset = 0;
209                 var indices = [], i=[];
210                 while {
211                         i = this.findRegexp(string, offset);
212                         i.notNil and: {i.size != 0}
213                 }{
214                         indices = indices.add(i);
215                         offset = i[0][0] + 1;
216                 }
217                 ^indices
218         }
220         find { arg string, ignoreCase = false, offset = 0;
221                 _String_Find
222                 ^this.primitiveFailed
223         }
224         findBackwards { arg string, ignoreCase = false, offset = 0x7FFFFFFE;
225                 _String_FindBackwards
226                 ^this.primitiveFailed
227         }
228         endsWith { arg string;
229                 ^this.contains(string, this.size - string.size)
230         }
231         beginsWith { arg string;
232                 ^this.containsStringAt(0, string)
233         }
234         findAll { arg string, ignoreCase = false, offset=0;
235                 var indices, i=0;
236                 while {
237                         i = this.find(string, ignoreCase, offset);
238                         i.notNil
239                 }{
240                         indices = indices.add(i);
241                         offset = i + 1;
242                 }
243                 ^indices
244         }
245         replace { arg find, replace;
246                 ^super.replace(find, replace).join
247         }
250         escapeChar { arg charToEscape; // $"
251                 _String_EscapeChar
252         }
254         quote {
255                 ^"\"" ++ this ++ "\""
256         }
257         tr { arg from,to;
258                 ^this.collect({ arg char;
259                         if(char == from,{to},{char})
260                 })
261         }
263         insert { arg index, string;
264                 ^this.keep(index) ++ string ++ this.drop(index)
265         }
267         wrapExtend { arg size;
268                 ^this.dup(size div: this.size).join
269         }
271         zeroPad {
272                 ^" " ++ this ++ " "
273         }
275         padLeft { arg size, string = " ";
276                 ^string.wrapExtend(max(0, size - this.size)) ++ this
277         }
279         padRight { arg size, string = " ";
280                 ^this ++ string.wrapExtend(max(0, size - this.size))
281         }
283         underlined { arg char = $-;
284                 ^this ++ "\n" ++ String.fill(this.size, char)
285         }
287         scramble {
288                 ^this.as(Array).scramble.as(String)
289         }
291         rotate { arg n = 1;
292                 ^this.as(Array).rotate(n).as(String)
293         }
295         compile { ^thisProcess.interpreter.compile(this); }
296         interpret { ^thisProcess.interpreter.interpret(this); }
297         interpretPrint { ^thisProcess.interpreter.interpretPrint(this); }
299         *readNew { arg file;
300                 ^file.readAllString;
301         }
302         prCat { arg aString; _ArrayCat }
304         printOn { arg stream;
305                 stream.putAll(this);
306         }
307         storeOn { arg stream;
308                 stream.putAll(this.asCompileString);
309         }
311         inspectorClass { ^StringInspector }
313         /// unix
315         standardizePath {
316                 _String_StandardizePath
317                 ^this.primitiveFailed
318         }
319         realPath {
320                 _String_RealPath
321                 ^this.primitiveFailed
322         }
323         withTrailingSlash {
324                 var sep = thisProcess.platform.pathSeparator;
325                 if(this.last != sep, {
326                         ^this ++ sep
327                 },{
328                         ^this
329                 })
330         }
331         withoutTrailingSlash {
332                 var sep = thisProcess.platform.pathSeparator;
333                 if(this.last == sep,{
334                         ^this.copyRange(0, this.size-2)
335                 },{
336                         ^this
337                 })
338         }
340         absolutePath {
341                 var first, sep;
342                 sep = thisProcess.platform.pathSeparator;
343                 first = this[0];
344                 if(first == sep){^this};
345                 if(first == $~){^this.standardizePath};
346                 ^File.getcwd ++ sep ++ this;
347         }
349         pathMatch { _StringPathMatch ^this.primitiveFailed } // glob
350         load {
351                 ^thisProcess.interpreter.executeFile(this);
352         }
353         loadPaths { |warn=true|
354                 var paths = this.pathMatch;
355                 if(warn and:{paths.isEmpty}) { ("no files found for this path:" + this.quote).warn };
356                 ^paths.collect({ arg path;
357                         thisProcess.interpreter.executeFile(path);
358                 });
359         }
360         loadRelative {
361                 var path = thisProcess.nowExecutingPath;
362                 if(path.isNil) { Error("can't load relative to an unsaved file").throw};
363                 if(path.basename == this) { Error("should not load a file from itself").throw };
364                 ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this).loadPaths
365         }
366         resolveRelative {
367                 var path, caller;
368                 caller = thisMethod.getBackTrace.caller.functionDef;
369                 if(caller == Interpreter.findMethod(\interpretPrintCmdLine), {
370                         path = thisProcess.nowExecutingPath;
371                 }, {
372                         path = caller.filenameSymbol.asString;
373                 });
374                 if(this[0] == thisProcess.platform.pathSeparator, {^this});
375                 if(path.isNil) { Error("can't resolve relative to an unsaved file").throw};
376                 ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this)
377         }
378         include {
379                 if(Quarks.isInstalled(this).not) {
380                         Quarks.install(this);
381                         "... the class library may have to be recompiled.".postln;
382                         // maybe check later whether there are .sc files included.
383                 }
384         }
385         exclude {
386                 if(Quarks.isInstalled(this)) {
387                         Quarks.uninstall(this);
388                         "... the class library may have to be recompiled.".postln;
389                 }
390         }
391         basename {
392                 _String_Basename;
393                 ^this.primitiveFailed
394         }
395         dirname {
396                 _String_Dirname;
397                 ^this.primitiveFailed
398         }
399         splitext {
400                 this.reverseDo({ arg char, i;
401                         if (char == $\., {
402                                 ^[this.copyFromStart(this.size - 2 - i), this.copyToEnd(this.size - i)]
403                         });
404                 });
405                 ^[this, nil]
406         }
408         // path concatenate
409         +/+ { arg path;
410                 var pathSeparator = thisProcess.platform.pathSeparator;
412                 if (path.respondsTo(\fullPath)) {
413                         ^PathName(this +/+ path.fullPath)
414                 };
416                 if (this.last == pathSeparator or: { path.first == pathSeparator }) {
417                         ^this ++ path
418                 };
420                 ^this ++ pathSeparator ++ path
421         }
423         asRelativePath { |relativeTo|
424                 ^PathName(this).asRelativePath(relativeTo)
425         }
426         asAbsolutePath {
427                         // changed because there is no need to create a separate object
428                         // when String already knows how to make an absolute path
429                 ^this.absolutePath;  // was ^PathName(this).asAbsolutePath
430         }
432         // runs a unix command and returns the result code.
433         systemCmd { _String_System ^this.primitiveFailed }
435         gethostbyname { _GetHostByName ^this.primitiveFailed }
437         // gets value of environment variable
438         getenv {
439                 _String_Getenv
440                 ^this.primitiveFailed
441         }
442         // sets value of environment variable
443         // value may be nil to unset the variable
444         setenv { arg value;
445                 _String_Setenv
446                 ^this.primitiveFailed
447         }
448         unsetenv {
449                 ^this.setenv(nil)
450         }
452         /// code gen
453         codegen_UGenCtorArg { arg stream;
454                 stream << this.asCompileString;
455         }
456         ugenCodeString { arg ugenIndex, isDecl, inputNames=#[], inputStrings=#[];
457                 _UGenCodeString
458                 ^this.primitiveFailed
459         }
461         asSecs { |maxDays = 365| // assume a timeString of ddd:hh:mm:ss.sss. see asTimeString.
462                 var time = 0, sign = 1, str = this;
463                 var limits = [inf, 60, 60, 24, maxDays];
464                 var scaling = [0.001, 1.0, 60.0, 3600.0, 86400.0];
465                 var padding = [3, 2, 2, 2, 3];
467                 if (this.first == $-) {
468                         str = this.drop(1);
469                         sign = -1
470                 };
472                 str.split($:).reverseDo { |num, i|
473                         num = num.padRight(padding[i], "0").asInteger;
474                         if (num > limits[i]) {
475                                 ("asSecs: number greater than allowed:" + this).warn;
476                                 num = limits[i];
477                         };
478                         if (num < 0) {
479                                 ("asSecs: negative numbers within slots not supported:" + this).warn;
480                                 num = 0;
481                         };
482                         time = time + (num * scaling[i]);
483                 };
484                 ^time * sign;
485         }
487         speak { arg channel = 0, force = false;
488                 var speech = GUI.current.speech;
489                 if( speech.initialized.not, { speech.init });
490                 speech.channels[ channel ].speak( this, force );
491         }
493         toLower {
494                 ^this.collect(_.toLower)
495         }
496         toUpper {
497                 ^this.collect(_.toUpper)
498         }
500         mkdir {
501                 _String_Mkdir
502                 ^this.primitiveFailed
503         }