]>
git.saurik.com Git - cycript.git/blob - Library.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "cycript.hpp"
35 #include "ConvertUTF.h"
38 #include "Execute.hpp"
39 #include "Pooling.hpp"
44 ::pthread_key_t CYLocal
<CYPool
>::key_
= Key_();
47 CYUTF8String
CYPoolUTF8String(CYPool
&pool
, CYUTF16String utf16
) {
49 size_t size(utf16
.size
* 5);
50 char *temp(new(pool
) char[size
]);
52 const uint16_t *lhs(utf16
.data
);
53 uint8_t *rhs(reinterpret_cast<uint8_t *>(temp
));
54 _assert(ConvertUTF16toUTF8(&lhs
, lhs
+ utf16
.size
, &rhs
, rhs
+ size
, lenientConversion
) == conversionOK
);
57 return CYUTF8String(temp
, reinterpret_cast<char *>(rhs
) - temp
);
60 CYUTF16String
CYPoolUTF16String(CYPool
&pool
, CYUTF8String utf8
) {
62 size_t size(utf8
.size
* 5);
63 uint16_t *temp(new (pool
) uint16_t[size
]);
65 const uint8_t *lhs(reinterpret_cast<const uint8_t *>(utf8
.data
));
67 _assert(ConvertUTF8toUTF16(&lhs
, lhs
+ utf8
.size
, &rhs
, rhs
+ size
, lenientConversion
) == conversionOK
);
70 return CYUTF16String(temp
, rhs
- temp
);
73 /* Index Offsets {{{ */
74 size_t CYGetIndex(const CYUTF8String
&value
) {
75 if (value
.data
[0] != '0') {
77 for (size_t i(0); i
!= value
.size
; ++i
) {
78 if (!DigitRange_
[value
.data
[i
]])
81 index
+= value
.data
[i
] - '0';
84 } else if (value
.size
== 1)
90 // XXX: this isn't actually right
91 bool CYGetOffset(const char *value
, ssize_t
&index
) {
92 if (value
[0] != '0') {
94 index
= strtol(value
, &end
, 10);
95 if (value
+ strlen(value
) == end
)
97 } else if (value
[1] == '\0') {
105 /* JavaScript *ify {{{ */
106 void CYStringify(std::ostringstream
&str
, const char *data
, size_t size
) {
107 unsigned quot(0), apos(0);
108 for (const char *value(data
), *end(data
+ size
); value
!= end
; ++value
)
111 else if (*value
== '\'')
114 bool single(quot
> apos
);
116 str
<< (single
? '\'' : '"');
118 for (const char *value(data
), *end(data
+ size
); value
!= end
; ++value
)
119 switch (uint8_t next
= *value
) {
120 case '\\': str
<< "\\\\"; break;
121 case '\b': str
<< "\\b"; break;
122 case '\f': str
<< "\\f"; break;
123 case '\n': str
<< "\\n"; break;
124 case '\r': str
<< "\\r"; break;
125 case '\t': str
<< "\\t"; break;
126 case '\v': str
<< "\\v"; break;
141 if (value
[1] >= '0' && value
[1] <= '9')
148 if (next
>= 0x20 && next
< 0x7f) simple
:
152 if ((next
& 0x80) != 0)
153 while ((next
& 0x80 >> ++levels
) != 0);
155 unsigned point(next
& 0xff >> levels
);
156 while (--levels
!= 0)
157 point
= point
<< 6 | uint8_t(*++value
) & 0x3f;
160 str
<< "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point
;
161 else if (point
< 0x10000)
162 str
<< "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point
;
165 str
<< "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point
>> 0x0a);
166 str
<< "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point
& 0x3ff);
171 str
<< (single
? '\'' : '"');
174 void CYNumerify(std::ostringstream
&str
, double value
) {
175 if (std::isinf(value
)) {
183 // XXX: I want this to print 1e3 rather than 1000
184 sprintf(string
, "%.17g", value
);
188 bool CYIsKey(CYUTF8String value
) {
189 const char *data(value
.data
);
190 size_t size(value
.size
);
195 if (DigitRange_
[data
[0]]) {
196 size_t index(CYGetIndex(value
));
197 if (index
== _not(size_t))
200 if (!WordStartRange_
[data
[0]])
202 for (size_t i(1); i
!= size
; ++i
)
203 if (!WordEndRange_
[data
[i
]])
211 double CYCastDouble(const char *value
, size_t size
) {
213 double number(strtod(value
, &end
));
214 if (end
!= value
+ size
)
219 double CYCastDouble(const char *value
) {
220 return CYCastDouble(value
, strlen(value
));
223 _visible
bool CYStartsWith(const CYUTF8String
&haystack
, const CYUTF8String
&needle
) {
224 return haystack
.size
>= needle
.size
&& strncmp(haystack
.data
, needle
.data
, needle
.size
) == 0;
227 CYUTF8String
CYPoolCode(CYPool
&pool
, std::istream
&stream
) {
229 CYDriver
driver(local
, stream
);
230 _assert(!driver
.Parse());
231 _assert(driver
.errors_
.empty());
234 CYContext
context(options
);
235 driver
.script_
->Replace(context
);
238 CYOutput
out(str
, options
);
239 out
<< *driver
.script_
;
240 return $pool
.strdup(str
.str().c_str());
243 CYPool
&CYGetGlobalPool() {
248 _visible
void CYThrow(const char *format
, ...) {
250 va_start(args
, format
);
251 throw CYPoolError(format
, args
);
252 // XXX: does this matter? :(
256 const char *CYPoolError::PoolCString(CYPool
&pool
) const {
257 return pool
.strdup(message_
);
260 CYPoolError::CYPoolError(const CYPoolError
&rhs
) :
261 message_(pool_
.strdup(rhs
.message_
))
265 CYPoolError::CYPoolError(const char *format
, ...) {
267 va_start(args
, format
);
268 // XXX: there might be a beter way to think about this
269 message_
= pool_
.vsprintf(64, format
, args
);
273 CYPoolError::CYPoolError(const char *format
, va_list args
) {
274 // XXX: there might be a beter way to think about this
275 message_
= pool_
.vsprintf(64, format
, args
);