]> git.saurik.com Git - cycript.git/blob - Library.cpp
Use start conditions to parse regular expressions.
[cycript.git] / Library.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
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.
11
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.
16
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/>.
19 **/
20 /* }}} */
21
22 #include <dlfcn.h>
23
24 #include "cycript.hpp"
25
26 #include "Pooling.hpp"
27
28 #include <sys/mman.h>
29
30 #include <iostream>
31 #include <set>
32 #include <map>
33 #include <iomanip>
34 #include <sstream>
35 #include <cmath>
36
37 #include "Driver.hpp"
38 #include "Error.hpp"
39 #include "Execute.hpp"
40 #include "Parser.hpp"
41 #include "String.hpp"
42
43 #include "ConvertUTF.h"
44
45 template <>
46 ::pthread_key_t CYLocal<CYPool>::key_ = Key_();
47
48 /* C Strings {{{ */
49 CYUTF8String CYPoolUTF8String(CYPool &pool, CYUTF16String utf16) {
50 // XXX: this is wrong
51 size_t size(utf16.size * 5);
52 char *temp(new(pool) char[size]);
53
54 const uint16_t *lhs(utf16.data);
55 uint8_t *rhs(reinterpret_cast<uint8_t *>(temp));
56 _assert(ConvertUTF16toUTF8(&lhs, lhs + utf16.size, &rhs, rhs + size, lenientConversion) == conversionOK);
57
58 *rhs = 0;
59 return CYUTF8String(temp, reinterpret_cast<char *>(rhs) - temp);
60 }
61
62 CYUTF16String CYPoolUTF16String(CYPool &pool, CYUTF8String utf8) {
63 // XXX: this is wrong
64 size_t size(utf8.size * 5);
65 uint16_t *temp(new (pool) uint16_t[size]);
66
67 const uint8_t *lhs(reinterpret_cast<const uint8_t *>(utf8.data));
68 uint16_t *rhs(temp);
69 _assert(ConvertUTF8toUTF16(&lhs, lhs + utf8.size, &rhs, rhs + size, lenientConversion) == conversionOK);
70
71 *rhs = 0;
72 return CYUTF16String(temp, rhs - temp);
73 }
74 /* }}} */
75 /* Index Offsets {{{ */
76 size_t CYGetIndex(const CYUTF8String &value) {
77 if (value.data[0] != '0') {
78 size_t index(0);
79 for (size_t i(0); i != value.size; ++i) {
80 if (!DigitRange_[value.data[i]])
81 return _not(size_t);
82 index *= 10;
83 index += value.data[i] - '0';
84 }
85 return index;
86 } else if (value.size == 1)
87 return 0;
88 else
89 return _not(size_t);
90 }
91
92 // XXX: this isn't actually right
93 bool CYGetOffset(const char *value, ssize_t &index) {
94 if (value[0] != '0') {
95 char *end;
96 index = strtol(value, &end, 10);
97 if (value + strlen(value) == end)
98 return true;
99 } else if (value[1] == '\0') {
100 index = 0;
101 return true;
102 }
103
104 return false;
105 }
106 /* }}} */
107 /* JavaScript *ify {{{ */
108 void CYStringify(std::ostringstream &str, const char *data, size_t size) {
109 unsigned quot(0), apos(0);
110 for (const char *value(data), *end(data + size); value != end; ++value)
111 if (*value == '"')
112 ++quot;
113 else if (*value == '\'')
114 ++apos;
115
116 bool single(quot > apos);
117
118 str << (single ? '\'' : '"');
119
120 for (const char *value(data), *end(data + size); value != end; ++value)
121 switch (uint8_t next = *value) {
122 case '\\': str << "\\\\"; break;
123 case '\b': str << "\\b"; break;
124 case '\f': str << "\\f"; break;
125 case '\n': str << "\\n"; break;
126 case '\r': str << "\\r"; break;
127 case '\t': str << "\\t"; break;
128 case '\v': str << "\\v"; break;
129
130 case '"':
131 if (!single)
132 str << "\\\"";
133 else goto simple;
134 break;
135
136 case '\'':
137 if (single)
138 str << "\\'";
139 else goto simple;
140 break;
141
142 case '\0':
143 if (value[1] >= '0' && value[1] <= '9')
144 str << "\\x00";
145 else
146 str << "\\0";
147 break;
148
149 default:
150 if (next >= 0x20 && next < 0x7f) simple:
151 str << *value;
152 else {
153 unsigned levels(1);
154 if ((next & 0x80) != 0)
155 while ((next & 0x80 >> ++levels) != 0);
156
157 unsigned point(next & 0xff >> levels);
158 while (--levels != 0)
159 point = point << 6 | uint8_t(*++value) & 0x3f;
160
161 if (point < 0x100)
162 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << point;
163 else if (point < 0x10000)
164 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << point;
165 else {
166 point -= 0x10000;
167 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xd800 | point >> 0x0a);
168 str << "\\u" << std::setbase(16) << std::setw(4) << std::setfill('0') << (0xdc00 | point & 0x3ff);
169 }
170 }
171 }
172
173 str << (single ? '\'' : '"');
174 }
175
176 void CYNumerify(std::ostringstream &str, double value) {
177 char string[32];
178 // XXX: I want this to print 1e3 rather than 1000
179 sprintf(string, "%.17g", value);
180 str << string;
181 }
182
183 bool CYIsKey(CYUTF8String value) {
184 const char *data(value.data);
185 size_t size(value.size);
186
187 if (size == 0)
188 return false;
189
190 if (DigitRange_[data[0]]) {
191 size_t index(CYGetIndex(value));
192 if (index == _not(size_t))
193 return false;
194 } else {
195 if (!WordStartRange_[data[0]])
196 return false;
197 for (size_t i(1); i != size; ++i)
198 if (!WordEndRange_[data[i]])
199 return false;
200 }
201
202 return true;
203 }
204 /* }}} */
205
206 double CYCastDouble(const char *value, size_t size) {
207 char *end;
208 double number(strtod(value, &end));
209 if (end != value + size)
210 return NAN;
211 return number;
212 }
213
214 double CYCastDouble(const char *value) {
215 return CYCastDouble(value, strlen(value));
216 }
217
218 CYUTF8String CYPoolCode(CYPool &pool, std::istream &stream) {
219 CYLocalPool local;
220 CYDriver driver(local, stream);
221 _assert(!driver.Parse());
222 _assert(driver.errors_.empty());
223
224 CYOptions options;
225 CYContext context(options);
226 driver.script_->Replace(context);
227
228 std::stringbuf str;
229 CYOutput out(str, options);
230 out << *driver.script_;
231 return $pool.strdup(str.str().c_str());
232 }
233
234 CYPool &CYGetGlobalPool() {
235 static CYPool pool;
236 return pool;
237 }
238
239 _visible void CYThrow(const char *format, ...) {
240 va_list args;
241 va_start(args, format);
242 throw CYPoolError(format, args);
243 // XXX: does this matter? :(
244 va_end(args);
245 }
246
247 const char *CYPoolError::PoolCString(CYPool &pool) const {
248 return pool.strdup(message_);
249 }
250
251 CYPoolError::CYPoolError(const CYPoolError &rhs) :
252 message_(pool_.strdup(rhs.message_))
253 {
254 }
255
256 CYPoolError::CYPoolError(const char *format, ...) {
257 va_list args;
258 va_start(args, format);
259 // XXX: there might be a beter way to think about this
260 message_ = pool_.vsprintf(64, format, args);
261 va_end(args);
262 }
263
264 CYPoolError::CYPoolError(const char *format, va_list args) {
265 // XXX: there might be a beter way to think about this
266 message_ = pool_.vsprintf(64, format, args);
267 }