]> git.saurik.com Git - cycript.git/blob - Library.cpp
Support Objective-C class extension syntax.
[cycript.git] / Library.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2010 Jay Freeman (saurik)
3 */
4
5 /* GNU Lesser General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <dlfcn.h>
23 #include <iconv.h>
24
25 #include "cycript.hpp"
26
27 #include "Pooling.hpp"
28
29 #include <sys/mman.h>
30
31 #include <iostream>
32 #include <ext/stdio_filebuf.h>
33 #include <set>
34 #include <map>
35 #include <iomanip>
36 #include <sstream>
37 #include <cmath>
38
39 #include "Parser.hpp"
40 #include "Cycript.tab.hh"
41
42 #include "Error.hpp"
43 #include "String.hpp"
44 #include "Execute.hpp"
45
46 /* C Strings {{{ */
47 template <typename Type_>
48 _finline size_t iconv_(size_t (*iconv)(iconv_t, Type_, size_t *, char **, size_t *), iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) {
49 return iconv(cd, const_cast<Type_>(inbuf), inbytesleft, outbuf, outbytesleft);
50 }
51
52 #ifdef __GLIBC__
53 #define UCS_2_INTERNAL "UCS-2"
54 #else
55 #define UCS_2_INTERNAL "UCS-2-INTERNAL"
56 #endif
57
58 CYUTF8String CYPoolUTF8String(apr_pool_t *pool, CYUTF16String utf16) {
59 _assert(pool != NULL);
60
61 const char *in(reinterpret_cast<const char *>(utf16.data));
62
63 iconv_t conversion(_syscall(iconv_open("UTF-8", UCS_2_INTERNAL)));
64
65 // XXX: this is wrong
66 size_t size(utf16.size * 5);
67 char *out(new(pool) char[size]);
68 CYUTF8String utf8(out, size);
69
70 size = utf16.size * 2;
71 _syscall(iconv_(&iconv, conversion, const_cast<char **>(&in), &size, &out, &utf8.size));
72
73 *out = '\0';
74 utf8.size = out - utf8.data;
75
76 _syscall(iconv_close(conversion));
77
78 return utf8;
79 }
80
81 CYUTF16String CYPoolUTF16String(apr_pool_t *pool, CYUTF8String utf8) {
82 _assert(pool != NULL);
83
84 const char *in(utf8.data);
85
86 iconv_t conversion(_syscall(iconv_open(UCS_2_INTERNAL, "UTF-8")));
87
88 // XXX: this is wrong
89 size_t size(utf8.size * 5);
90 uint16_t *temp(new (pool) uint16_t[size]);
91 CYUTF16String utf16(temp, size * 2);
92 char *out(reinterpret_cast<char *>(temp));
93
94 size = utf8.size;
95 _syscall(iconv_(&iconv, conversion, const_cast<char **>(&in), &size, &out, &utf16.size));
96
97 utf16.size = reinterpret_cast<uint16_t *>(out) - utf16.data;
98 temp[utf16.size] = 0;
99
100 _syscall(iconv_close(conversion));
101
102 return utf16;
103 }
104 /* }}} */
105 /* Index Offsets {{{ */
106 size_t CYGetIndex(const CYUTF8String &value) {
107 if (value.data[0] != '0') {
108 size_t index(0);
109 for (size_t i(0); i != value.size; ++i) {
110 if (!DigitRange_[value.data[i]])
111 return _not(size_t);
112 index *= 10;
113 index += value.data[i] - '0';
114 }
115 return index;
116 } else if (value.size == 1)
117 return 0;
118 else
119 return _not(size_t);
120 }
121
122 // XXX: this isn't actually right
123 bool CYGetOffset(const char *value, ssize_t &index) {
124 if (value[0] != '0') {
125 char *end;
126 index = strtol(value, &end, 10);
127 if (value + strlen(value) == end)
128 return true;
129 } else if (value[1] == '\0') {
130 index = 0;
131 return true;
132 }
133
134 return false;
135 }
136 /* }}} */
137 /* JavaScript *ify {{{ */
138 void CYStringify(std::ostringstream &str, const char *data, size_t size) {
139 unsigned quot(0), apos(0);
140 for (const char *value(data), *end(data + size); value != end; ++value)
141 if (*value == '"')
142 ++quot;
143 else if (*value == '\'')
144 ++apos;
145
146 bool single(quot > apos);
147
148 str << (single ? '\'' : '"');
149
150 for (const char *value(data), *end(data + size); value != end; ++value)
151 switch (*value) {
152 case '\\': str << "\\\\"; break;
153 case '\b': str << "\\b"; break;
154 case '\f': str << "\\f"; break;
155 case '\n': str << "\\n"; break;
156 case '\r': str << "\\r"; break;
157 case '\t': str << "\\t"; break;
158 case '\v': str << "\\v"; break;
159
160 case '"':
161 if (!single)
162 str << "\\\"";
163 else goto simple;
164 break;
165
166 case '\'':
167 if (single)
168 str << "\\'";
169 else goto simple;
170 break;
171
172 default:
173 // this test is designed to be "awesome", generating neither warnings nor incorrect results
174 if (*value < 0x20 || *value >= 0x7f)
175 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(uint8_t(*value));
176 else simple:
177 str << *value;
178 }
179
180 str << (single ? '\'' : '"');
181 }
182
183 void CYNumerify(std::ostringstream &str, double value) {
184 char string[32];
185 // XXX: I want this to print 1e3 rather than 1000
186 sprintf(string, "%.17g", value);
187 str << string;
188 }
189
190 bool CYIsKey(CYUTF8String value) {
191 const char *data(value.data);
192 size_t size(value.size);
193
194 if (size == 0)
195 return false;
196
197 if (DigitRange_[data[0]]) {
198 size_t index(CYGetIndex(value));
199 if (index == _not(size_t))
200 return false;
201 } else {
202 if (!WordStartRange_[data[0]])
203 return false;
204 for (size_t i(1); i != size; ++i)
205 if (!WordEndRange_[data[i]])
206 return false;
207 }
208
209 return true;
210 }
211 /* }}} */
212
213 double CYCastDouble(const char *value, size_t size) {
214 char *end;
215 double number(strtod(value, &end));
216 if (end != value + size)
217 return NAN;
218 return number;
219 }
220
221 double CYCastDouble(const char *value) {
222 return CYCastDouble(value, strlen(value));
223 }
224
225 extern "C" void CydgetPoolParse(apr_pool_t *remote, const uint16_t **data, size_t *size) {
226 CYLocalPool local;
227
228 CYDriver driver;
229 cy::parser parser(driver);
230
231 CYUTF8String utf8(CYPoolUTF8String(local, CYUTF16String(*data, *size)));
232
233 driver.data_ = utf8.data;
234 driver.size_ = utf8.size;
235
236 if (parser.parse() != 0 || !driver.errors_.empty())
237 return;
238
239 CYOptions options;
240 CYContext context(options);
241 driver.program_->Replace(context);
242 std::ostringstream str;
243 CYOutput out(str, options);
244 out << *driver.program_;
245 std::string code(str.str());
246
247 CYUTF16String utf16(CYPoolUTF16String(remote, CYUTF8String(code.c_str(), code.size())));
248
249 *data = utf16.data;
250 *size = utf16.size;
251 }
252
253 static apr_pool_t *Pool_;
254
255 static bool initialized_;
256
257 void CYInitializeStatic() {
258 if (!initialized_)
259 initialized_ = true;
260 else return;
261
262 _aprcall(apr_initialize());
263 _aprcall(apr_pool_create(&Pool_, NULL));
264 }
265
266 apr_pool_t *CYGetGlobalPool() {
267 CYInitializeStatic();
268 return Pool_;
269 }
270
271 void CYThrow(const char *format, ...) {
272 va_list args;
273 va_start(args, format);
274 throw CYPoolError(format, args);
275 // XXX: does this matter? :(
276 va_end(args);
277 }
278
279 const char *CYPoolError::PoolCString(apr_pool_t *pool) const {
280 return apr_pstrdup(pool, message_);
281 }
282
283 CYPoolError::CYPoolError(const char *format, ...) {
284 va_list args;
285 va_start(args, format);
286 message_ = apr_pvsprintf(pool_, format, args);
287 va_end(args);
288 }
289
290 CYPoolError::CYPoolError(const char *format, va_list args) {
291 message_ = apr_pvsprintf(pool_, format, args);
292 }