common: prevent buffer overflow
[supercollider.git] / lang / LangPrimSource / PyrStringPrim.cpp
blob1b8b4ceac088480c2cd0f154914766e881edbb73
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/filesystem/path.hpp>
43 #include <boost/filesystem/operations.hpp>
44 #include <boost/regex.hpp>
45 #include <boost/intrusive/list.hpp>
46 #include <boost/intrusive/unordered_set.hpp>
48 #include <string>
49 #include <vector>
51 using namespace std;
53 int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed);
54 int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed)
56 PyrSlot *a;
57 char str[1024], *strp=0;
58 int len;
60 a = g->sp;
61 len = slotRawObject(a)->size;
62 strp = len > 1023 ? (char*)malloc(len+1) : str;
64 memcpy(strp, slotRawString(a)->s, len);
65 strp[len] = 0;
67 SetSymbol(a, getsym(strp));
69 if (len > 1023) free(strp);
71 return errNone;
74 int prString_AsInteger(struct VMGlobals *g, int numArgsPushed);
75 int prString_AsInteger(struct VMGlobals *g, int numArgsPushed)
77 PyrSlot *a = g->sp;
79 char str[256];
80 int err = slotStrVal(a, str, 255);
81 if (err) return err;
83 SetInt(a, atoi(str));
85 return errNone;
88 int prString_AsFloat(struct VMGlobals *g, int numArgsPushed);
89 int prString_AsFloat(struct VMGlobals *g, int numArgsPushed)
91 PyrSlot *a = g->sp;
93 char str[256];
94 int err = slotStrVal(a, str, 255);
95 if (err) return err;
97 SetFloat(a, atof(str));
99 return errNone;
102 int prString_AsCompileString(struct VMGlobals *g, int numArgsPushed)
104 PyrSlot *a = g->sp;
105 PyrString* scstr = slotRawString(a);
106 char *chars1 = scstr->s;
107 int newSize = scstr->size + 2;
108 for (int i=0; i<scstr->size; ++i) {
109 if (chars1[i] == '"' || chars1[i] == '\\') newSize++;
111 PyrString *newString = newPyrStringN(g->gc, newSize, 0, true);
112 char *chars2 = newString->s;
113 chars2[0] = '"';
114 chars2[newSize - 1] = '"';
115 int k = 1;
116 for (int i=0; i<scstr->size; ++i) {
117 int c = chars1[i];
118 if (c == '"' || c == '\\') chars2[k++] = '\\';
119 chars2[k++] = c;
121 SetObject(a, newString);
122 return errNone;
125 int prString_Format(struct VMGlobals *g, int numArgsPushed)
127 PyrSlot *a = g->sp - 1;
128 PyrSlot *b = g->sp;
130 if (!isKindOfSlot(b, class_array)) return errWrongType;
132 char *fmt = slotRawString(a)->s;
134 int asize = slotRawObject(a)->size;
135 int bsize = slotRawObject(b)->size;
136 int csize = asize;
138 PyrSlot *slots = slotRawObject(b)->slots;
139 for (int i=0; i<bsize; ++i) {
140 PyrSlot *slot = slots + i;
141 if (!isKindOfSlot(slot, class_string)) return errWrongType;
142 csize += slotRawString(slot)->size;
144 PyrString *newString = newPyrStringN(g->gc, csize, 0, true);
145 char* buf = newString->s;
147 int k=0;
148 int index = 0;
149 for (int i=0; i<asize;) {
150 char ch = fmt[i++];
151 if (ch == '%') {
152 if (index < bsize) {
153 PyrString* bstring = slotRawString(&slots[index]);
154 memcpy(buf+k, bstring->s, bstring->size);
155 k += bstring->size;
156 index++;
158 } else if (ch == '\\') {
159 if (i >= asize) break;
160 ch = fmt[i++];
161 if (ch == '%') {
162 buf[k++] = '%';
163 } else {
164 i--;
166 } else {
167 buf[k++] = ch;
170 newString->size = k;
171 SetObject(a, newString);
172 return errNone;
175 namespace detail {
177 namespace bin = boost::intrusive;
179 class regex_lru_cache
181 int regex_flags;
183 struct regex_node:
184 bin::list_base_hook<>,
185 bin::unordered_set_base_hook<>
187 public:
188 regex_node(const char * str, size_t size, int regex_flags):
189 pattern(str, size, regex_flags)
192 boost::regex const & get (void) const
194 return pattern;
197 private:
198 boost::regex pattern;
201 struct regex_equal
203 bool operator()(regex_node const & lhs, regex_node const & rhs) const
205 return lhs.get() == rhs.get();
208 bool operator()(const char * lhs, regex_node const & rhs) const
210 return strcmp(lhs, rhs.get().str().c_str()) == 0;
214 static inline std::size_t string_hash(const char * str)
216 std::size_t ret = 0;
218 // sdbm hash
219 int c;
220 while ((c = *str++))
221 ret = c + (ret << 6) + (ret << 16) - ret;
223 return ret;
226 struct regex_hash
228 size_t operator()(regex_node const & arg) const
230 return string_hash(arg.get().str().c_str());
233 size_t operator()(const char * arg) const
235 return string_hash(arg);
239 typedef bin::unordered_set<regex_node, bin::equal<regex_equal>, bin::hash<regex_hash>,
240 bin::power_2_buckets<true>, bin::constant_time_size<false> >
241 re_set_t;
242 typedef re_set_t::bucket_type bucket_type;
243 typedef re_set_t::bucket_traits bucket_traits;
244 bucket_type buckets[128];
245 re_set_t re_set;
247 bin::list<regex_node> re_list;
249 void pop_lru()
251 regex_node & rlu = re_list.back();
252 re_list.pop_back();
253 re_set.erase(rlu);
254 delete &rlu;
257 public:
258 regex_lru_cache(int regex_flags = boost::regex_constants::ECMAScript):
259 re_set(bucket_traits(buckets, 128))
262 ~regex_lru_cache()
264 while (!re_list.empty()) {
265 pop_lru();
269 boost::regex const & get_regex(const char * str, size_t size)
271 re_set_t::iterator re_in_cache = re_set.find(str, regex_hash(), regex_equal());
272 if (re_in_cache != re_set.end()) {
273 regex_node & node = *re_in_cache;
274 bin::list<regex_node>::iterator re_in_list = bin::list<regex_node>::s_iterator_to(node);
276 re_list.splice(re_list.begin(), re_list, re_in_list); // move to the begin of the list
277 assert(&re_list.front() == &node);
278 return node.get();
281 if (re_list.size() >= 64)
282 pop_lru();
284 regex_node * new_node = new regex_node(str, size, regex_flags);
285 re_set.insert(*new_node);
286 re_list.push_front(*new_node);
287 return new_node->get();
293 int prString_Regexp(struct VMGlobals *g, int numArgsPushed)
295 /* not reentrant */
296 static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript | boost::regex_constants::nosubs);
298 using namespace boost;
300 int err, start, end, ret, len;
302 PyrSlot *a = g->sp - 3;
303 PyrSlot *b = g->sp - 2;
304 PyrSlot *c = g->sp - 1;
305 PyrSlot *d = g->sp;
307 if (!isKindOfSlot(b, class_string)) return errWrongType;
308 if (NotInt(c) || (NotInt(d) && NotNil(d))) return errWrongType;
309 start = slotRawInt(c);
311 len = slotRawObject(b)->size; // last char index instead of size
313 if(IsNil(d)) {
314 end = len;
315 } else {
316 end = slotRawInt(d);
319 if(end > len)
320 end = len;
322 if(end - start <= 0) {
323 SetFalse(a);
324 return errNone;
327 int stringlen = end - start;
329 try {
330 regex const & pattern = regex_lru_cache.get_regex(slotRawString(a)->s, slotRawObject(a)->size);
331 match_flag_type flags = match_nosubs | match_any;
333 const char * stringStart = slotRawString(b)->s + start;
334 const char * stringEnd = stringStart + stringlen;
335 bool res = regex_search(stringStart, stringEnd, pattern, flags);
337 if(res)
338 SetTrue(a);
339 else
340 SetFalse(a);
342 return errNone;
343 } catch (std::exception const & e) {
344 postfl("Warning: Exception in _String_Regexp - %s\n", e.what());
345 return errFailed;
349 struct sc_regexp_match {
350 int pos;
351 int len;
355 static int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed)
357 /* not reentrant */
358 static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript);
360 using namespace boost;
362 PyrSlot *a = g->sp - 2; // source string
363 PyrSlot *b = g->sp - 1; // pattern
364 PyrSlot *c = g->sp; // offset
366 if (!isKindOfSlot(b, class_string) || (NotInt(c))) return errWrongType;
368 int offset = slotRawInt(c);
369 int stringlen = std::max(slotRawObject(a)->size - offset, 0);
370 int patternsize = slotRawObject(b)->size + 1;
372 std::vector<sc_regexp_match> matches;
373 const char* const stringBegin = slotRawString(a)->s + offset;
374 try {
375 regex const & pattern = regex_lru_cache.get_regex(slotRawString(b)->s, slotRawObject(b)->size);
376 match_flag_type flags = match_default;
378 match_results<const char*> what;
379 const char* start = stringBegin;
380 const char* end = start + stringlen;
381 while (start <= end && regex_search(start, end, what, pattern, flags))
383 for (int i = 0; i < what.size(); ++i )
385 sc_regexp_match match;
386 if (what[i].matched) {
387 match.pos = what[i].first - stringBegin;
388 match.len = what[i].second - what[i].first;
389 } else {
390 match.pos = 0;
391 match.len = 0;
393 matches.push_back(match);
395 start = what[0].second;
396 if(what[0].first == what[0].second) ++start;
398 } catch (std::exception const & e) {
399 postfl("Warning: Exception in _String_FindRegexp - %s\n", e.what());
400 return errFailed;
403 int match_count = matches.size();
405 PyrObject *result_array = newPyrArray(g->gc, match_count, 0, true);
406 result_array->size = 0;
407 SetObject(a, result_array);
409 if( !match_count ) return errNone;
411 for (int i = 0; i < match_count; ++i )
413 int pos = matches[i].pos;
414 int len = matches[i].len;
416 PyrObject *array = newPyrArray(g->gc, 2, 0, true);
417 SetObject(result_array->slots + i, array);
418 result_array->size++;
419 g->gc->GCWrite(result_array, array);
421 PyrString *matched_string = newPyrStringN(g->gc, len, 0, true);
422 memcpy(matched_string->s, stringBegin + pos, len);
424 array->size = 2;
425 SetInt(array->slots, pos + offset);
426 SetObject(array->slots+1, matched_string);
427 g->gc->GCWrite(array, matched_string);
430 return errNone;
433 int memcmpi(char *a, char *b, int len)
435 for (int i=0; i<len; ++i) {
436 char aa = toupper(a[i]);
437 char bb = toupper(b[i]);
438 if (aa < bb) return -1;
439 if (aa > bb) return 1;
441 return 0;
444 int prStringCompare(struct VMGlobals *g, int numArgsPushed);
445 int prStringCompare(struct VMGlobals *g, int numArgsPushed)
447 PyrSlot *a, *b, *c;
448 int cmp, length;
450 a = g->sp - 2;
451 b = g->sp - 1;
452 c = g->sp;
454 if (NotObj(b) || !isKindOf(slotRawObject(b), class_string)) {
455 SetNil(a);
456 return errNone;
458 length = sc_min(slotRawObject(a)->size, slotRawObject(b)->size);
459 if (IsTrue(c)) cmp = memcmpi(slotRawString(a)->s, slotRawString(b)->s, length);
460 else cmp = memcmp(slotRawString(a)->s, slotRawString(b)->s, length);
461 if (cmp == 0) {
462 if (slotRawObject(a)->size < slotRawObject(b)->size) cmp = -1;
463 else if (slotRawObject(a)->size > slotRawObject(b)->size) cmp = 1;
465 SetInt(a, cmp);
466 return errNone;
469 int prStringHash(struct VMGlobals *g, int numArgsPushed);
470 int prStringHash(struct VMGlobals *g, int numArgsPushed)
472 PyrSlot *a = g->sp;
473 int hash = Hash(slotRawString(a)->s, slotRawString(a)->size);
474 SetInt(a, hash);
475 return errNone;
478 #ifndef SC_WIN32
479 #include <glob.h>
481 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed);
482 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed)
484 PyrSlot *a = g->sp;
486 char pattern[1024];
487 int err = slotStrVal(a, pattern, 1023);
488 if (err) return err;
490 glob_t pglob;
492 int gflags = GLOB_MARK | GLOB_TILDE;
493 #ifdef SC_DARWIN
494 gflags |= GLOB_QUOTE;
495 #endif
497 int gerr = glob(pattern, gflags, NULL, &pglob);
498 if (gerr) {
499 pglob.gl_pathc = 0;
501 PyrObject* array = newPyrArray(g->gc, pglob.gl_pathc, 0, true);
502 SetObject(a, array);
503 if (gerr) return errNone;
505 for (unsigned int i=0; i<pglob.gl_pathc; ++i) {
506 PyrObject *string = (PyrObject*)newPyrString(g->gc, pglob.gl_pathv[i], 0, true);
507 SetObject(array->slots+i, string);
508 g->gc->GCWrite(array, string);
509 array->size++;
512 globfree(&pglob);
514 return errNone;
516 #else //#ifndef SC_WIN32
517 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed);
519 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed)
521 PyrSlot *a = g->sp;
523 char pattern[1024];
524 int err = slotStrVal(a, pattern, 1023);
525 if (err) return err;
527 win32_ReplaceCharInString(pattern,1024,'/','\\');
528 // Remove trailing slash if found, to allow folders to be matched
529 if(pattern[strlen(pattern)-1]=='\\'){
530 pattern[strlen(pattern)-1] = 0;
532 // extract the containing folder, including backslash
533 char folder[1024];
534 win32_ExtractContainingFolder(folder,pattern,1024);
536 ///////// PASS 1
538 WIN32_FIND_DATA findData;
539 HANDLE hFind;
540 int nbPaths = 0;
542 hFind = ::FindFirstFile(pattern, &findData);
543 if (hFind == INVALID_HANDLE_VALUE) {
544 nbPaths = 0;
547 if (hFind == INVALID_HANDLE_VALUE) {
548 // This is what happens when no matches. So we create an empty array to return.
549 PyrObject* array = newPyrArray(g->gc, 0, 0, true);
550 SetObject(a, array);
551 return errNone;
554 do {
555 if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, "..")!=0){
556 nbPaths++;
558 } while( ::FindNextFile(hFind, &findData));
559 ::FindClose(hFind);
561 // PASS 2
563 hFind = ::FindFirstFile(pattern, &findData);
564 if (hFind == INVALID_HANDLE_VALUE) {
565 nbPaths = 0;
568 PyrObject* array = newPyrArray(g->gc, nbPaths , 0, true);
569 SetObject(a, array);
570 if (hFind == INVALID_HANDLE_VALUE) {
571 return errNone;
574 int i = 0;
575 do {
576 if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, ".")!=0){
577 std::string strPath(folder);
578 strPath += std::string(findData.cFileName);
579 if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
580 strPath += std::string("\\"); // Append trailing slash, to match behaviour on unix (used by sclang to detect folderness)
582 const char* fullPath = strPath.c_str();
583 PyrObject *string = (PyrObject*)newPyrString(g->gc, fullPath, 0, true);
584 SetObject(array->slots+i, string);
585 g->gc->GCWrite(array, string);
586 array->size++;
587 i++;
589 } while( ::FindNextFile(hFind, &findData));
590 ::FindClose(hFind);
591 return errNone;
593 #endif //#ifndef SC_WIN32
595 int prString_Getenv(struct VMGlobals* g, int numArgsPushed);
596 int prString_Getenv(struct VMGlobals* g, int /* numArgsPushed */)
598 PyrSlot* arg = g->sp;
599 char key[256];
600 char* value;
601 int err;
603 err = slotStrVal(arg, key, 256);
604 if (err) return err;
606 value = getenv(key);
608 if (value) {
609 PyrString* pyrString = newPyrString(g->gc, value, 0, true);
610 if (!pyrString) return errFailed;
611 SetObject(arg, pyrString);
612 } else {
613 SetNil(arg);
616 return errNone;
619 int prString_Setenv(struct VMGlobals* g, int numArgsPushed);
620 int prString_Setenv(struct VMGlobals* g, int /* numArgsPushed */)
622 PyrSlot* args = g->sp - 1;
623 char key[256];
624 int err;
626 err = slotStrVal(args+0, key, 256);
627 if (err) return err;
629 if (IsNil(args+1)) {
630 #ifdef SC_WIN32
631 SetEnvironmentVariable(key,NULL);
632 #else
633 unsetenv(key);
634 #endif
635 } else {
636 char value[1024];
637 err = slotStrVal(args+1, value, 1024);
638 if (err) return err;
639 #ifdef SC_WIN32
640 SetEnvironmentVariable(key, value);
641 #else
642 setenv(key, value, 1);
643 #endif
646 return errNone;
649 int prStripRtf(struct VMGlobals *g, int numArgsPushed);
650 int prStripRtf(struct VMGlobals *g, int numArgsPushed)
652 PyrSlot *a = g->sp;
653 int len = slotRawObject(a)->size;
654 char * chars = (char*)malloc(len + 1);
655 memcpy(chars, slotRawString(a)->s, len);
656 chars[len] = 0;
657 rtf2txt(chars);
659 PyrString* string = newPyrString(g->gc, chars, 0, false);
660 SetObject(a, string);
661 free(chars);
663 return errNone;
666 int prStripHtml(struct VMGlobals *g, int numArgsPushed);
667 int prStripHtml(struct VMGlobals *g, int numArgsPushed)
669 PyrSlot *a = g->sp;
670 int len = slotRawObject(a)->size;
671 char * chars = (char*)malloc(len + 1);
672 memcpy(chars, slotRawString(a)->s, len);
673 chars[len] = 0;
674 html2txt(chars);
676 PyrString* string = newPyrString(g->gc, chars, 0, false);
677 SetObject(a, string);
678 free(chars);
680 return errNone;
684 int prString_GetResourceDirPath(struct VMGlobals *g, int numArgsPushed);
685 int prString_GetResourceDirPath(struct VMGlobals *g, int numArgsPushed)
687 PyrSlot *a = g->sp;
689 char * chars = (char*)malloc(MAXPATHLEN - 32);
690 sc_GetResourceDirectory(chars, MAXPATHLEN - 32);
692 PyrString* string = newPyrString(g->gc, chars, 0, false);
693 SetObject(a, string);
694 free(chars);
696 return errNone;
700 int prString_Find(struct VMGlobals *g, int numArgsPushed);
701 int prString_Find(struct VMGlobals *g, int numArgsPushed)
703 PyrSlot *a = g->sp - 3; // source string
704 PyrSlot *b = g->sp - 2; // search string
705 PyrSlot *c = g->sp - 1; // ignoreCase
706 PyrSlot *d = g->sp; // offset
708 int offset;
709 int err = slotIntVal(d, &offset);
710 if (err) return err;
712 if (!isKindOfSlot(b, class_string)) {
713 SetNil(a);
714 return errNone;
717 int alength = slotRawObject(a)->size - offset;
718 int blength = slotRawObject(b)->size;
720 if ((alength <= 0)
721 || (blength == 0)
722 // should also return nil if search string is longer than source
723 || (blength > alength))
725 SetNil(a);
726 return errNone;
729 int cmp = 1; // assume contains will be false
730 char *achar = slotRawString(a)->s + offset;
731 char *bchar = slotRawString(b)->s;
732 char bchar0 = bchar[0];
733 int scanlength = alength - blength;
734 if (IsTrue(c)) {
735 bchar0 = toupper(bchar0);
736 for (int i=0; i <= scanlength; ++i, ++achar) {
737 if (toupper(*achar) == bchar0) {
738 cmp = memcmpi(achar+1, bchar+1, blength-1);
739 if (cmp == 0) break;
742 } else {
743 for (int i=0; i <= scanlength; ++i, ++achar) {
744 if (*achar == bchar0) {
745 cmp = memcmp(achar+1, bchar+1, blength-1);
746 if (cmp == 0) break;
750 if (cmp == 0) {
751 SetInt(a, achar - slotRawString(a)->s);
752 } else {
753 SetNil(a);
755 return errNone;
758 int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed);
759 int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed)
761 PyrSlot *a = g->sp - 3; // source string
762 PyrSlot *b = g->sp - 2; // search string
763 PyrSlot *c = g->sp - 1; // ignoreCase
764 PyrSlot *d = g->sp; // offset
766 int offset;
767 int err = slotIntVal(d, &offset);
768 if (err) return err;
770 if (!isKindOfSlot(b, class_string)) {
771 SetNil(a);
772 return errNone;
775 int alength = sc_min(offset + 1, slotRawObject(a)->size);
776 int blength = slotRawObject(b)->size;
778 if ((alength <= 0)
779 || (blength == 0)
780 // should also return nil if search string is longer than source
781 || (blength > alength))
783 SetNil(a);
784 return errNone;
787 int cmp = 1; // assume contains will be false
788 char *achar = slotRawString(a)->s + (alength - blength);
789 char *bchar = slotRawString(b)->s;
790 char bchar0 = bchar[0];
791 int scanlength = alength - blength;
792 if (IsTrue(c)) {
793 bchar0 = toupper(bchar0);
794 for (int i=scanlength; i >= 0; --i, --achar) {
795 if (toupper(*achar) == bchar0) {
796 cmp = memcmpi(achar+1, bchar+1, blength-1);
797 if (cmp == 0) break;
800 } else {
801 for (int i=scanlength; i >= 0; --i, --achar) {
802 if (*achar == bchar0) {
803 cmp = memcmp(achar+1, bchar+1, blength-1);
804 if (cmp == 0) break;
808 if (cmp == 0) {
809 SetInt(a, achar - slotRawString(a)->s);
810 } else {
811 SetNil(a);
813 return errNone;
816 #if SC_DARWIN
817 # include <CoreFoundation/CoreFoundation.h>
818 #endif // SC_DARWIN
820 int prString_StandardizePath(struct VMGlobals* g, int numArgsPushed);
821 int prString_StandardizePath(struct VMGlobals* g, int /* numArgsPushed */)
823 PyrSlot* arg = g->sp;
824 char ipath[PATH_MAX];
825 char opathbuf[PATH_MAX];
826 char* opath = opathbuf;
827 int err;
829 err = slotStrVal(arg, ipath, PATH_MAX);
830 if (err) return err;
832 if (!sc_StandardizePath(ipath, opath)) {
833 opath = ipath;
836 #if SC_DARWIN
837 CFStringRef cfstring =
838 CFStringCreateWithCString(NULL,
839 opath,
840 kCFStringEncodingUTF8);
841 err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX);
842 CFRelease(cfstring);
843 if (err) return errFailed;
844 #endif // SC_DARWIN
846 PyrString* pyrString = newPyrString(g->gc, opath, 0, true);
847 SetObject(arg, pyrString);
849 return errNone;
852 int prString_RealPath(struct VMGlobals* g, int numArgsPushed )
854 PyrSlot* arg = g->sp;
855 char ipath[PATH_MAX];
856 char opath[PATH_MAX];
857 int err;
859 err = slotStrVal(arg, ipath, PATH_MAX);
860 if (err) return err;
862 bool isAlias = false;
863 if(sc_ResolveIfAlias(ipath, opath, isAlias, PATH_MAX)!=0) {
864 return errFailed;
867 boost::system::error_code error_code;
868 boost::filesystem::path p = boost::filesystem::canonical(opath,error_code);
869 if(error_code) {
870 SetNil(arg);
871 return errNone;
873 strcpy(opath,p.string().c_str());
875 #if SC_DARWIN
876 CFStringRef cfstring =
877 CFStringCreateWithCString(NULL,
878 opath,
879 kCFStringEncodingUTF8);
880 err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX);
881 CFRelease(cfstring);
882 if (err) return errFailed;
883 #endif // SC_DARWIN
885 PyrString* pyrString = newPyrString(g->gc, opath, 0, true);
886 SetObject(arg, pyrString);
888 return errNone;
891 int prString_EscapeChar(struct VMGlobals* g, int numArgsPushed)
893 PyrSlot* arg = g->sp - 1;
894 PyrSlot* charToEscapeSlot = g->sp;
896 assert (isKindOfSlot(arg, class_string));
898 if (!IsChar(charToEscapeSlot))
899 return errWrongType;
901 char charToEscape = slotRawChar(charToEscapeSlot);
903 PyrString* argString = slotRawString(arg);
904 int length = argString->size;
905 PyrString* resultString = newPyrStringN(g->gc, length*2 + 1, 0, 1); // pressimize
907 char * original = argString->s;
908 char * result = resultString->s;
910 int resultLength = length;
911 for (int i = 0; i != length; ++i) {
912 char current = *original++;
913 if (current == charToEscape) {
914 *result++ = '\\';
915 resultLength += 1;
917 *result++ = current;
919 *result = 0;
921 resultString->size = resultLength;
923 SetRaw(arg, (PyrObject*)resultString);
925 return errNone;
928 int prString_mkdir(struct VMGlobals * g, int numArgsPushed)
930 PyrSlot* arg = g->sp;
932 char argString[MAXPATHLEN];
933 int error = slotStrVal(arg, argString, MAXPATHLEN);
934 if (error != errNone)
935 return error;
937 boost::system::error_code error_code;
938 boost::filesystem::create_directories(argString, error_code);
939 if (error_code)
940 postfl("Warning: %s (\"%s\")\n", error_code.message().c_str(), argString);
942 return errNone;
946 void initStringPrimitives();
947 void initStringPrimitives()
949 int base, index = 0;
951 base = nextPrimitiveIndex();
953 definePrimitive(base, index++, "_StringCompare", prStringCompare, 3, 0);
954 definePrimitive(base, index++, "_StringHash", prStringHash, 1, 0);
955 definePrimitive(base, index++, "_StringPathMatch", prStringPathMatch, 1, 0);
956 definePrimitive(base, index++, "_StringAsSymbol", prStringAsSymbol, 1, 0);
957 definePrimitive(base, index++, "_String_AsInteger", prString_AsInteger, 1, 0);
958 definePrimitive(base, index++, "_String_AsFloat", prString_AsFloat, 1, 0);
959 definePrimitive(base, index++, "_String_AsCompileString", prString_AsCompileString, 1, 0);
960 definePrimitive(base, index++, "_String_Getenv", prString_Getenv, 1, 0);
961 definePrimitive(base, index++, "_String_Setenv", prString_Setenv, 2, 0);
962 definePrimitive(base, index++, "_String_Find", prString_Find, 4, 0);
963 definePrimitive(base, index++, "_String_FindBackwards", prString_FindBackwards, 4, 0);
964 definePrimitive(base, index++, "_String_Format", prString_Format, 2, 0);
965 definePrimitive(base, index++, "_String_Regexp", prString_Regexp, 4, 0);
966 definePrimitive(base, index++, "_String_FindRegexp", prString_FindRegexp, 3, 0);
967 definePrimitive(base, index++, "_StripRtf", prStripRtf, 1, 0);
968 definePrimitive(base, index++, "_StripHtml", prStripHtml, 1, 0);
969 definePrimitive(base, index++, "_String_GetResourceDirPath", prString_GetResourceDirPath, 1, 0);
970 definePrimitive(base, index++, "_String_StandardizePath", prString_StandardizePath, 1, 0);
971 definePrimitive(base, index++, "_String_RealPath", prString_RealPath, 1, 0);
972 definePrimitive(base, index++, "_String_EscapeChar", prString_EscapeChar, 2, 0);
973 definePrimitive(base, index++, "_String_Mkdir", prString_mkdir, 1, 0);
976 #if _SC_PLUGINS_
979 #include "SCPlugin.h"
981 // export the function that SC will call to load the plug in.
982 #pragma export on
983 extern "C" { SCPlugIn* loadPlugIn(void); }
984 #pragma export off
987 // define plug in object
988 class APlugIn : public SCPlugIn
990 public:
991 APlugIn();
992 virtual ~APlugIn();
994 virtual void AboutToCompile();
997 APlugIn::APlugIn()
999 // constructor for plug in
1002 APlugIn::~APlugIn()
1004 // destructor for plug in
1007 void APlugIn::AboutToCompile()
1009 // this is called each time the class library is compiled.
1010 initStringPrimitives();
1013 // This function is called when the plug in is loaded into SC.
1014 // It returns an instance of APlugIn.
1015 SCPlugIn* loadPlugIn()
1017 return new APlugIn();
1020 #endif