cmake: supernova - missing include_directories() for Jack
[supercollider.git] / lang / LangPrimSource / PyrStringPrim.cpp
blobbfa6d0afdba67cfc4b218dc06956cf41acebabbc
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 Primitives for String.
26 #include "PyrPrimitive.h"
27 #include "PyrKernel.h"
28 #include "GC.h"
29 #include "Hash.h"
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include "PyrLexer.h"
34 #include "SC_DirUtils.h"
35 #ifdef SC_WIN32
36 # include <direct.h>
37 # include "SC_Win32Utils.h"
38 #else
39 # include <sys/param.h>
40 #endif
42 #include <boost/regex.hpp>
43 #include <boost/intrusive/list.hpp>
44 #include <boost/intrusive/unordered_set.hpp>
46 #include <string>
47 #include <vector>
49 using namespace std;
51 int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed);
52 int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed)
54 PyrSlot *a;
55 char str[1024], *strp=0;
56 int len;
58 a = g->sp;
59 len = slotRawObject(a)->size;
60 strp = len > 1023 ? (char*)malloc(len+1) : str;
62 memcpy(strp, slotRawString(a)->s, len);
63 strp[len] = 0;
65 SetSymbol(a, getsym(strp));
67 if (len > 1023) free(strp);
69 return errNone;
72 int prString_AsInteger(struct VMGlobals *g, int numArgsPushed);
73 int prString_AsInteger(struct VMGlobals *g, int numArgsPushed)
75 PyrSlot *a = g->sp;
77 char str[256];
78 int err = slotStrVal(a, str, 255);
79 if (err) return err;
81 SetInt(a, atoi(str));
83 return errNone;
86 int prString_AsFloat(struct VMGlobals *g, int numArgsPushed);
87 int prString_AsFloat(struct VMGlobals *g, int numArgsPushed)
89 PyrSlot *a = g->sp;
91 char str[256];
92 int err = slotStrVal(a, str, 255);
93 if (err) return err;
95 SetFloat(a, atof(str));
97 return errNone;
100 int prString_AsCompileString(struct VMGlobals *g, int numArgsPushed)
102 PyrSlot *a = g->sp;
103 PyrString* scstr = slotRawString(a);
104 char *chars1 = scstr->s;
105 int newSize = scstr->size + 2;
106 for (int i=0; i<scstr->size; ++i) {
107 if (chars1[i] == '"' || chars1[i] == '\\') newSize++;
109 PyrString *newString = newPyrStringN(g->gc, newSize, 0, true);
110 char *chars2 = newString->s;
111 chars2[0] = '"';
112 chars2[newSize - 1] = '"';
113 int k = 1;
114 for (int i=0; i<scstr->size; ++i) {
115 int c = chars1[i];
116 if (c == '"' || c == '\\') chars2[k++] = '\\';
117 chars2[k++] = c;
119 SetObject(a, newString);
120 return errNone;
123 int prString_Format(struct VMGlobals *g, int numArgsPushed)
125 PyrSlot *a = g->sp - 1;
126 PyrSlot *b = g->sp;
128 if (!isKindOfSlot(b, class_array)) return errWrongType;
130 char *fmt = slotRawString(a)->s;
132 int asize = slotRawObject(a)->size;
133 int bsize = slotRawObject(b)->size;
134 int csize = asize;
136 PyrSlot *slots = slotRawObject(b)->slots;
137 for (int i=0; i<bsize; ++i) {
138 PyrSlot *slot = slots + i;
139 if (!isKindOfSlot(slot, class_string)) return errWrongType;
140 csize += slotRawString(slot)->size;
142 PyrString *newString = newPyrStringN(g->gc, csize, 0, true);
143 char* buf = newString->s;
145 int k=0;
146 int index = 0;
147 for (int i=0; i<asize;) {
148 char ch = fmt[i++];
149 if (ch == '%') {
150 if (index < bsize) {
151 PyrString* bstring = slotRawString(&slots[index]);
152 memcpy(buf+k, bstring->s, bstring->size);
153 k += bstring->size;
154 index++;
156 } else if (ch == '\\') {
157 if (i >= asize) break;
158 ch = fmt[i++];
159 if (ch == '%') {
160 buf[k++] = '%';
161 } else {
162 i--;
164 } else {
165 buf[k++] = ch;
168 newString->size = k;
169 SetObject(a, newString);
170 return errNone;
173 namespace detail {
175 namespace bin = boost::intrusive;
177 class regex_lru_cache
179 int regex_flags;
181 struct regex_node:
182 bin::list_base_hook<>,
183 bin::unordered_set_base_hook<>
185 public:
186 regex_node(const char * str, size_t size, int regex_flags):
187 pattern(str, size, regex_flags)
190 boost::regex const & get (void) const
192 return pattern;
195 private:
196 boost::regex pattern;
199 struct regex_equal
201 bool operator()(regex_node const & lhs, regex_node const & rhs) const
203 return lhs.get() == rhs.get();
206 bool operator()(const char * lhs, regex_node const & rhs) const
208 return strcmp(lhs, rhs.get().str().c_str()) == 0;
212 static inline std::size_t string_hash(const char * str)
214 std::size_t ret = 0;
216 // sdbm hash
217 int c;
218 while ((c = *str++))
219 ret = c + (ret << 6) + (ret << 16) - ret;
221 return ret;
224 struct regex_hash
226 size_t operator()(regex_node const & arg) const
228 return string_hash(arg.get().str().c_str());
231 size_t operator()(const char * arg) const
233 return string_hash(arg);
237 typedef bin::unordered_set<regex_node, bin::equal<regex_equal>, bin::hash<regex_hash>,
238 bin::power_2_buckets<true>, bin::constant_time_size<false> >
239 re_set_t;
240 typedef re_set_t::bucket_type bucket_type;
241 typedef re_set_t::bucket_traits bucket_traits;
242 bucket_type buckets[128];
243 re_set_t re_set;
245 bin::list<regex_node> re_list;
247 void pop_lru()
249 regex_node & rlu = re_list.back();
250 re_list.pop_back();
251 re_set.erase(rlu);
252 delete &rlu;
255 public:
256 regex_lru_cache(int regex_flags = boost::regex_constants::ECMAScript):
257 re_set(bucket_traits(buckets, 128))
260 ~regex_lru_cache()
262 while (!re_list.empty()) {
263 pop_lru();
267 boost::regex const & get_regex(const char * str, size_t size)
269 re_set_t::iterator re_in_cache = re_set.find(str, regex_hash(), regex_equal());
270 if (re_in_cache != re_set.end()) {
271 regex_node & node = *re_in_cache;
272 bin::list<regex_node>::iterator re_in_list = bin::list<regex_node>::s_iterator_to(node);
274 re_list.splice(re_list.begin(), re_list, re_in_list); // move to the begin of the list
275 assert(&re_list.front() == &node);
276 return node.get();
279 if (re_list.size() >= 64)
280 pop_lru();
282 regex_node * new_node = new regex_node(str, size, regex_flags);
283 re_set.insert(*new_node);
284 re_list.push_front(*new_node);
285 return new_node->get();
291 int prString_Regexp(struct VMGlobals *g, int numArgsPushed)
293 /* not reentrant */
294 static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript | boost::regex_constants::nosubs);
296 using namespace boost;
298 int err, start, end, ret, len;
300 PyrSlot *a = g->sp - 3;
301 PyrSlot *b = g->sp - 2;
302 PyrSlot *c = g->sp - 1;
303 PyrSlot *d = g->sp;
305 if (!isKindOfSlot(b, class_string)) return errWrongType;
306 if (NotInt(c) || (NotInt(d) && NotNil(d))) return errWrongType;
307 start = slotRawInt(c);
309 len = slotRawObject(b)->size; // last char index instead of size
311 if(IsNil(d)) {
312 end = len;
313 } else {
314 end = slotRawInt(d);
317 if(end > len)
318 end = len;
320 if(end - start <= 0) {
321 SetFalse(a);
322 return errNone;
325 int stringlen = end - start;
327 try {
328 regex const & pattern = regex_lru_cache.get_regex(slotRawString(a)->s, slotRawObject(a)->size);
329 match_flag_type flags = match_nosubs | match_any;
331 const char * stringStart = slotRawString(b)->s + start;
332 const char * stringEnd = stringStart + stringlen;
333 bool res = regex_search(stringStart, stringEnd, pattern, flags);
335 if(res)
336 SetTrue(a);
337 else
338 SetFalse(a);
340 return errNone;
341 } catch (std::exception const & e) {
342 postfl("Warning: Exception in _String_Regexp - %s\n", e.what());
343 return errFailed;
347 struct sc_regexp_match {
348 int pos;
349 int len;
353 static int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed)
355 /* not reentrant */
356 static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript);
358 using namespace boost;
360 PyrSlot *a = g->sp - 2; // source string
361 PyrSlot *b = g->sp - 1; // pattern
362 PyrSlot *c = g->sp; // offset
364 if (!isKindOfSlot(b, class_string) || (NotInt(c))) return errWrongType;
366 int offset = slotRawInt(c);
367 int stringlen = std::max(slotRawObject(a)->size - offset, 0);
368 int patternsize = slotRawObject(b)->size + 1;
370 std::vector<sc_regexp_match> matches;
371 const char* const stringBegin = slotRawString(a)->s + offset;
372 try {
373 regex const & pattern = regex_lru_cache.get_regex(slotRawString(b)->s, slotRawObject(b)->size);
374 match_flag_type flags = match_default;
376 match_results<const char*> what;
377 const char* start = stringBegin;
378 const char* end = start + stringlen;
379 while (start <= end && regex_search(start, end, what, pattern, flags))
381 for (int i = 0; i < what.size(); ++i )
383 sc_regexp_match match;
384 if (what[i].matched) {
385 match.pos = what[i].first - stringBegin;
386 match.len = what[i].second - what[i].first;
387 } else {
388 match.pos = 0;
389 match.len = 0;
391 matches.push_back(match);
393 start = what[0].second;
394 if(what[0].first == what[0].second) ++start;
396 } catch (std::exception const & e) {
397 postfl("Warning: Exception in _String_FindRegexp - %s\n", e.what());
398 return errFailed;
401 int match_count = matches.size();
403 PyrObject *result_array = newPyrArray(g->gc, match_count, 0, true);
404 result_array->size = 0;
405 SetObject(a, result_array);
407 if( !match_count ) return errNone;
409 for (int i = 0; i < match_count; ++i )
411 int pos = matches[i].pos;
412 int len = matches[i].len;
414 PyrObject *array = newPyrArray(g->gc, 2, 0, true);
415 SetObject(result_array->slots + i, array);
416 result_array->size++;
417 g->gc->GCWrite(result_array, array);
419 PyrString *matched_string = newPyrStringN(g->gc, len, 0, true);
420 memcpy(matched_string->s, stringBegin + pos, len);
422 array->size = 2;
423 SetInt(array->slots, pos + offset);
424 SetObject(array->slots+1, matched_string);
425 g->gc->GCWrite(array, matched_string);
428 return errNone;
431 int memcmpi(char *a, char *b, int len)
433 for (int i=0; i<len; ++i) {
434 char aa = toupper(a[i]);
435 char bb = toupper(b[i]);
436 if (aa < bb) return -1;
437 if (aa > bb) return 1;
439 return 0;
442 int prStringCompare(struct VMGlobals *g, int numArgsPushed);
443 int prStringCompare(struct VMGlobals *g, int numArgsPushed)
445 PyrSlot *a, *b, *c;
446 int cmp, length;
448 a = g->sp - 2;
449 b = g->sp - 1;
450 c = g->sp;
452 if (NotObj(b) || !isKindOf(slotRawObject(b), class_string)) {
453 SetNil(a);
454 return errNone;
456 length = sc_min(slotRawObject(a)->size, slotRawObject(b)->size);
457 if (IsTrue(c)) cmp = memcmpi(slotRawString(a)->s, slotRawString(b)->s, length);
458 else cmp = memcmp(slotRawString(a)->s, slotRawString(b)->s, length);
459 if (cmp == 0) {
460 if (slotRawObject(a)->size < slotRawObject(b)->size) cmp = -1;
461 else if (slotRawObject(a)->size > slotRawObject(b)->size) cmp = 1;
463 SetInt(a, cmp);
464 return errNone;
467 int prStringHash(struct VMGlobals *g, int numArgsPushed);
468 int prStringHash(struct VMGlobals *g, int numArgsPushed)
470 PyrSlot *a = g->sp;
471 int hash = Hash(slotRawString(a)->s, slotRawString(a)->size);
472 SetInt(a, hash);
473 return errNone;
476 #ifndef SC_WIN32
477 #include <glob.h>
479 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed);
480 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed)
482 PyrSlot *a = g->sp;
484 char pattern[1024];
485 int err = slotStrVal(a, pattern, 1023);
486 if (err) return err;
488 glob_t pglob;
490 int gflags = GLOB_MARK | GLOB_TILDE;
491 #ifdef SC_DARWIN
492 gflags |= GLOB_QUOTE;
493 #endif
495 int gerr = glob(pattern, gflags, NULL, &pglob);
496 if (gerr) {
497 pglob.gl_pathc = 0;
499 PyrObject* array = newPyrArray(g->gc, pglob.gl_pathc, 0, true);
500 SetObject(a, array);
501 if (gerr) return errNone;
503 for (unsigned int i=0; i<pglob.gl_pathc; ++i) {
504 PyrObject *string = (PyrObject*)newPyrString(g->gc, pglob.gl_pathv[i], 0, true);
505 SetObject(array->slots+i, string);
506 g->gc->GCWrite(array, string);
507 array->size++;
510 globfree(&pglob);
512 return errNone;
514 #else //#ifndef SC_WIN32
515 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed);
517 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed)
519 PyrSlot *a = g->sp;
521 char pattern[1024];
522 int err = slotStrVal(a, pattern, 1023);
523 if (err) return err;
525 win32_ReplaceCharInString(pattern,1024,'/','\\');
526 // Remove trailing slash if found, to allow folders to be matched
527 if(pattern[strlen(pattern)-1]=='\\'){
528 pattern[strlen(pattern)-1] = 0;
530 // extract the containing folder, including backslash
531 char folder[1024];
532 win32_ExtractContainingFolder(folder,pattern,1024);
534 ///////// PASS 1
536 WIN32_FIND_DATA findData;
537 HANDLE hFind;
538 int nbPaths = 0;
540 hFind = ::FindFirstFile(pattern, &findData);
541 if (hFind == INVALID_HANDLE_VALUE) {
542 nbPaths = 0;
545 if (hFind == INVALID_HANDLE_VALUE) {
546 // This is what happens when no matches. So we create an empty array to return.
547 PyrObject* array = newPyrArray(g->gc, 0, 0, true);
548 SetObject(a, array);
549 return errNone;
552 do {
553 if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, "..")!=0){
554 nbPaths++;
556 } while( ::FindNextFile(hFind, &findData));
557 ::FindClose(hFind);
559 // PASS 2
561 hFind = ::FindFirstFile(pattern, &findData);
562 if (hFind == INVALID_HANDLE_VALUE) {
563 nbPaths = 0;
566 PyrObject* array = newPyrArray(g->gc, nbPaths , 0, true);
567 SetObject(a, array);
568 if (hFind == INVALID_HANDLE_VALUE) {
569 return errNone;
572 int i = 0;
573 do {
574 if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, ".")!=0){
575 std::string strPath(folder);
576 strPath += std::string(findData.cFileName);
577 if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
578 strPath += std::string("\\"); // Append trailing slash, to match behaviour on unix (used by sclang to detect folderness)
580 const char* fullPath = strPath.c_str();
581 PyrObject *string = (PyrObject*)newPyrString(g->gc, fullPath, 0, true);
582 SetObject(array->slots+i, string);
583 g->gc->GCWrite(array, string);
584 array->size++;
585 i++;
587 } while( ::FindNextFile(hFind, &findData));
588 ::FindClose(hFind);
589 return errNone;
591 #endif //#ifndef SC_WIN32
593 int prString_Getenv(struct VMGlobals* g, int numArgsPushed);
594 int prString_Getenv(struct VMGlobals* g, int /* numArgsPushed */)
596 PyrSlot* arg = g->sp;
597 char key[256];
598 char* value;
599 int err;
601 err = slotStrVal(arg, key, 256);
602 if (err) return err;
604 value = getenv(key);
606 if (value) {
607 PyrString* pyrString = newPyrString(g->gc, value, 0, true);
608 if (!pyrString) return errFailed;
609 SetObject(arg, pyrString);
610 } else {
611 SetNil(arg);
614 return errNone;
617 int prString_Setenv(struct VMGlobals* g, int numArgsPushed);
618 int prString_Setenv(struct VMGlobals* g, int /* numArgsPushed */)
620 PyrSlot* args = g->sp - 1;
621 char key[256];
622 int err;
624 err = slotStrVal(args+0, key, 256);
625 if (err) return err;
627 if (IsNil(args+1)) {
628 #ifdef SC_WIN32
629 SetEnvironmentVariable(key,NULL);
630 #else
631 unsetenv(key);
632 #endif
633 } else {
634 char value[1024];
635 err = slotStrVal(args+1, value, 1024);
636 if (err) return err;
637 #ifdef SC_WIN32
638 SetEnvironmentVariable(key, value);
639 #else
640 setenv(key, value, 1);
641 #endif
644 return errNone;
647 int prStripRtf(struct VMGlobals *g, int numArgsPushed);
648 int prStripRtf(struct VMGlobals *g, int numArgsPushed)
650 PyrSlot *a = g->sp;
651 int len = slotRawObject(a)->size;
652 char * chars = (char*)malloc(len + 1);
653 memcpy(chars, slotRawString(a)->s, len);
654 chars[len] = 0;
655 rtf2txt(chars);
657 PyrString* string = newPyrString(g->gc, chars, 0, false);
658 SetObject(a, string);
659 free(chars);
661 return errNone;
664 int prStripHtml(struct VMGlobals *g, int numArgsPushed);
665 int prStripHtml(struct VMGlobals *g, int numArgsPushed)
667 PyrSlot *a = g->sp;
668 int len = slotRawObject(a)->size;
669 char * chars = (char*)malloc(len + 1);
670 memcpy(chars, slotRawString(a)->s, len);
671 chars[len] = 0;
672 html2txt(chars);
674 PyrString* string = newPyrString(g->gc, chars, 0, false);
675 SetObject(a, string);
676 free(chars);
678 return errNone;
682 int prString_GetResourceDirPath(struct VMGlobals *g, int numArgsPushed);
683 int prString_GetResourceDirPath(struct VMGlobals *g, int numArgsPushed)
685 PyrSlot *a = g->sp;
687 char * chars = (char*)malloc(MAXPATHLEN - 32);
688 sc_GetResourceDirectory(chars, MAXPATHLEN - 32);
690 PyrString* string = newPyrString(g->gc, chars, 0, false);
691 SetObject(a, string);
692 free(chars);
694 return errNone;
698 int prString_Find(struct VMGlobals *g, int numArgsPushed);
699 int prString_Find(struct VMGlobals *g, int numArgsPushed)
701 PyrSlot *a = g->sp - 3; // source string
702 PyrSlot *b = g->sp - 2; // search string
703 PyrSlot *c = g->sp - 1; // ignoreCase
704 PyrSlot *d = g->sp; // offset
706 int offset;
707 int err = slotIntVal(d, &offset);
708 if (err) return err;
710 if (!isKindOfSlot(b, class_string)) {
711 SetNil(a);
712 return errNone;
715 int alength = slotRawObject(a)->size - offset;
716 int blength = slotRawObject(b)->size;
718 if ((alength <= 0)
719 || (blength == 0)
720 // should also return nil if search string is longer than source
721 || (blength > alength))
723 SetNil(a);
724 return errNone;
727 int cmp = 1; // assume contains will be false
728 char *achar = slotRawString(a)->s + offset;
729 char *bchar = slotRawString(b)->s;
730 char bchar0 = bchar[0];
731 int scanlength = alength - blength;
732 if (IsTrue(c)) {
733 bchar0 = toupper(bchar0);
734 for (int i=0; i <= scanlength; ++i, ++achar) {
735 if (toupper(*achar) == bchar0) {
736 cmp = memcmpi(achar+1, bchar+1, blength-1);
737 if (cmp == 0) break;
740 } else {
741 for (int i=0; i <= scanlength; ++i, ++achar) {
742 if (*achar == bchar0) {
743 cmp = memcmp(achar+1, bchar+1, blength-1);
744 if (cmp == 0) break;
748 if (cmp == 0) {
749 SetInt(a, achar - slotRawString(a)->s);
750 } else {
751 SetNil(a);
753 return errNone;
756 int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed);
757 int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed)
759 PyrSlot *a = g->sp - 3; // source string
760 PyrSlot *b = g->sp - 2; // search string
761 PyrSlot *c = g->sp - 1; // ignoreCase
762 PyrSlot *d = g->sp; // offset
764 int offset;
765 int err = slotIntVal(d, &offset);
766 if (err) return err;
768 if (!isKindOfSlot(b, class_string)) {
769 SetNil(a);
770 return errNone;
773 int alength = sc_min(offset + 1, slotRawObject(a)->size);
774 int blength = slotRawObject(b)->size;
776 if ((alength <= 0)
777 || (blength == 0)
778 // should also return nil if search string is longer than source
779 || (blength > alength))
781 SetNil(a);
782 return errNone;
785 int cmp = 1; // assume contains will be false
786 char *achar = slotRawString(a)->s + (alength - blength);
787 char *bchar = slotRawString(b)->s;
788 char bchar0 = bchar[0];
789 int scanlength = alength - blength;
790 if (IsTrue(c)) {
791 bchar0 = toupper(bchar0);
792 for (int i=scanlength; i >= 0; --i, --achar) {
793 if (toupper(*achar) == bchar0) {
794 cmp = memcmpi(achar+1, bchar+1, blength-1);
795 if (cmp == 0) break;
798 } else {
799 for (int i=scanlength; i >= 0; --i, --achar) {
800 if (*achar == bchar0) {
801 cmp = memcmp(achar+1, bchar+1, blength-1);
802 if (cmp == 0) break;
806 if (cmp == 0) {
807 SetInt(a, achar - slotRawString(a)->s);
808 } else {
809 SetNil(a);
811 return errNone;
814 #if SC_DARWIN
815 # include <CoreFoundation/CoreFoundation.h>
816 #endif // SC_DARWIN
818 int prString_StandardizePath(struct VMGlobals* g, int numArgsPushed);
819 int prString_StandardizePath(struct VMGlobals* g, int /* numArgsPushed */)
821 PyrSlot* arg = g->sp;
822 char ipath[PATH_MAX];
823 char opathbuf[PATH_MAX];
824 char* opath = opathbuf;
825 int err;
827 err = slotStrVal(arg, ipath, PATH_MAX);
828 if (err) return err;
830 if (!sc_StandardizePath(ipath, opath)) {
831 opath = ipath;
834 #if SC_DARWIN
835 CFStringRef cfstring =
836 CFStringCreateWithCString(NULL,
837 opath,
838 kCFStringEncodingUTF8);
839 err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX);
840 CFRelease(cfstring);
841 if (err) return errFailed;
842 #endif // SC_DARWIN
844 PyrString* pyrString = newPyrString(g->gc, opath, 0, true);
845 SetObject(arg, pyrString);
847 return errNone;
850 int prString_EscapeChar(struct VMGlobals* g, int numArgsPushed)
852 PyrSlot* arg = g->sp - 1;
853 PyrSlot* charToEscapeSlot = g->sp;
855 assert (isKindOfSlot(arg, class_string));
857 if (!IsChar(charToEscapeSlot))
858 return errWrongType;
860 char charToEscape = slotRawChar(charToEscapeSlot);
862 PyrString* argString = slotRawString(arg);
863 int length = argString->size;
864 PyrString* resultString = newPyrStringN(g->gc, length*2 + 1, 0, 1); // pressimize
866 char * original = argString->s;
867 char * result = resultString->s;
869 int resultLength = length;
870 for (int i = 0; i != length; ++i) {
871 char current = *original++;
872 if (current == charToEscape) {
873 *result++ = '\\';
874 resultLength += 1;
876 *result++ = current;
878 *result = 0;
880 resultString->size = resultLength;
882 SetRaw(arg, (PyrObject*)resultString);
884 return errNone;
888 void initStringPrimitives();
889 void initStringPrimitives()
891 int base, index = 0;
893 base = nextPrimitiveIndex();
895 definePrimitive(base, index++, "_StringCompare", prStringCompare, 3, 0);
896 definePrimitive(base, index++, "_StringHash", prStringHash, 1, 0);
897 definePrimitive(base, index++, "_StringPathMatch", prStringPathMatch, 1, 0);
898 definePrimitive(base, index++, "_StringAsSymbol", prStringAsSymbol, 1, 0);
899 definePrimitive(base, index++, "_String_AsInteger", prString_AsInteger, 1, 0);
900 definePrimitive(base, index++, "_String_AsFloat", prString_AsFloat, 1, 0);
901 definePrimitive(base, index++, "_String_AsCompileString", prString_AsCompileString, 1, 0);
902 definePrimitive(base, index++, "_String_Getenv", prString_Getenv, 1, 0);
903 definePrimitive(base, index++, "_String_Setenv", prString_Setenv, 2, 0);
904 definePrimitive(base, index++, "_String_Find", prString_Find, 4, 0);
905 definePrimitive(base, index++, "_String_FindBackwards", prString_FindBackwards, 4, 0);
906 definePrimitive(base, index++, "_String_Format", prString_Format, 2, 0);
907 definePrimitive(base, index++, "_String_Regexp", prString_Regexp, 4, 0);
908 definePrimitive(base, index++, "_String_FindRegexp", prString_FindRegexp, 3, 0);
909 definePrimitive(base, index++, "_StripRtf", prStripRtf, 1, 0);
910 definePrimitive(base, index++, "_StripHtml", prStripHtml, 1, 0);
911 definePrimitive(base, index++, "_String_GetResourceDirPath", prString_GetResourceDirPath, 1, 0);
912 definePrimitive(base, index++, "_String_StandardizePath", prString_StandardizePath, 1, 0);
913 definePrimitive(base, index++, "_String_EscapeChar", prString_EscapeChar, 2, 0);
916 #if _SC_PLUGINS_
919 #include "SCPlugin.h"
921 // export the function that SC will call to load the plug in.
922 #pragma export on
923 extern "C" { SCPlugIn* loadPlugIn(void); }
924 #pragma export off
927 // define plug in object
928 class APlugIn : public SCPlugIn
930 public:
931 APlugIn();
932 virtual ~APlugIn();
934 virtual void AboutToCompile();
937 APlugIn::APlugIn()
939 // constructor for plug in
942 APlugIn::~APlugIn()
944 // destructor for plug in
947 void APlugIn::AboutToCompile()
949 // this is called each time the class library is compiled.
950 initStringPrimitives();
953 // This function is called when the plug in is loaded into SC.
954 // It returns an instance of APlugIn.
955 SCPlugIn* loadPlugIn()
957 return new APlugIn();
960 #endif