]> git.saurik.com Git - cycript.git/blame - Application.mm
Fixed [4 longLongValue] == 1.522122665807053e+16.
[cycript.git] / Application.mm
CommitLineData
057f943f
JF
1#define _GNU_SOURCE
2
693d501b 3#include <substrate.h>
30ddc20c 4#include "cycript.hpp"
057f943f
JF
5
6#include <cstdio>
7#include <sstream>
8
9#include <setjmp.h>
10
11#include <readline/readline.h>
12#include <readline/history.h>
13
b09da87b
JF
14#include <sys/mman.h>
15
16#include <errno.h>
17#include <unistd.h>
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
057f943f
JF
23#include "Cycript.tab.hh"
24
25static jmp_buf ctrlc_;
26
579ed526 27static void sigint(int) {
057f943f
JF
28 longjmp(ctrlc_, 1);
29}
30
579ed526
JF
31static JSStringRef Result_;
32
4cf49641 33void Run(const char *code, FILE *fout) { _pooled
b09da87b
JF
34 JSStringRef script(JSStringCreateWithUTF8CString(code));
35
36 JSContextRef context(CYGetJSContext());
37
38 JSValueRef exception(NULL);
39 JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception));
40 JSStringRelease(script);
41
4cf49641 42 if (exception != NULL) { error:
b09da87b 43 result = exception;
4cf49641
JF
44 exception = NULL;
45 }
b09da87b
JF
46
47 if (!JSValueIsUndefined(context, result)) {
478d4ed0
JF
48 CYPool pool;
49 const char *json;
b09da87b 50
4cf49641
JF
51 json = CYPoolJSONString(pool, context, result, &exception);
52 if (exception != NULL)
53 goto error;
b09da87b 54
579ed526
JF
55 CYSetProperty(context, CYGetGlobalObject(context), Result_, result);
56
b09da87b 57 if (fout != NULL) {
478d4ed0 58 fputs(json, fout);
b09da87b
JF
59 fputs("\n", fout);
60 fflush(fout);
61 }
b09da87b
JF
62 }
63}
64
579ed526 65static void Console() {
1f8eae40
JF
66 bool bypass(false);
67 bool debug(false);
68
057f943f
JF
69 FILE *fout(stdout);
70
71 rl_bind_key('\t', rl_insert);
72
73 struct sigaction action;
74 sigemptyset(&action.sa_mask);
75 action.sa_handler = &sigint;
76 action.sa_flags = 0;
77 sigaction(SIGINT, &action, NULL);
78
79 restart: for (;;) {
80 std::string command;
81 std::vector<std::string> lines;
82
931b816a
JF
83 bool extra(false);
84 const char *prompt("cy# ");
85
057f943f
JF
86 if (setjmp(ctrlc_) != 0) {
87 fputs("\n", fout);
88 fflush(fout);
89 goto restart;
90 }
91
057f943f
JF
92 read:
93 char *line(readline(prompt));
94 if (line == NULL)
95 break;
931b816a
JF
96
97 if (!extra) {
98 extra = true;
99 if (line[0] == '\\') {
1f8eae40
JF
100 std::string data(line + 1);
101 if (data == "bypass") {
102 bypass = !bypass;
103 fprintf(fout, "bypass == %s\n", bypass ? "true" : "false");
104 fflush(fout);
105 } else if (data == "debug") {
106 debug = !debug;
107 fprintf(fout, "debug == %s\n", debug ? "true" : "false");
108 fflush(fout);
109 }
d35a3b07 110 add_history(line);
931b816a
JF
111 goto restart;
112 }
113 }
114
057f943f
JF
115 lines.push_back(line);
116 command += line;
117 free(line);
118
1f8eae40
JF
119 std::string code;
120
121 if (bypass)
122 code = command;
123 else {
124 CYDriver driver("");
125 cy::parser parser(driver);
126
127 driver.data_ = command.c_str();
128 driver.size_ = command.size();
129
130 if (parser.parse() != 0 || !driver.errors_.empty()) {
131 for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) {
132 cy::position begin(i->location_.begin);
133 if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) {
134 std::cerr << i->message_ << std::endl;
135 add_history(command.c_str());
136 goto restart;
137 }
138 }
057f943f 139
1f8eae40 140 driver.errors_.clear();
057f943f 141
1f8eae40
JF
142 command += '\n';
143 prompt = "cy> ";
144 goto read;
057f943f
JF
145 }
146
1f8eae40
JF
147 if (driver.source_ == NULL)
148 goto restart;
057f943f 149
1f8eae40
JF
150 std::ostringstream str;
151 driver.source_->Show(str);
152 code = str.str();
057f943f
JF
153 }
154
057f943f
JF
155 add_history(command.c_str());
156
1f8eae40
JF
157 if (debug)
158 std::cout << code << std::endl;
057f943f 159
b09da87b
JF
160 Run(code.c_str(), fout);
161 }
057f943f 162
b09da87b
JF
163 fputs("\n", fout);
164 fflush(fout);
165}
057f943f 166
579ed526 167static void *Map(const char *path, size_t *psize) {
b09da87b
JF
168 int fd;
169 _syscall(fd = open(path, O_RDONLY));
057f943f 170
b09da87b
JF
171 struct stat stat;
172 _syscall(fstat(fd, &stat));
173 size_t size(stat.st_size);
057f943f 174
b09da87b 175 *psize = size;
057f943f 176
b09da87b
JF
177 void *base;
178 _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
057f943f 179
b09da87b
JF
180 _syscall(close(fd));
181 return base;
182}
057f943f 183
b09da87b
JF
184int main(int argc, const char *argv[]) {
185 const char *script;
186
187 if (argc == 1)
188 script = NULL;
189 else {
190 CYSetArgs(argc - 1, argv + 1);
191 script = argv[1];
192 }
193
579ed526
JF
194 Result_ = CYCopyJSString("_");
195
b09da87b
JF
196 if (script == NULL || strcmp(script, "-") == 0)
197 Console();
198 else {
199 CYDriver driver(script);
200 cy::parser parser(driver);
201
202 size_t size;
203 char *start(reinterpret_cast<char *>(Map(script, &size)));
204 char *end(start + size);
205
206 if (size >= 2 && start[0] == '#' && start[1] == '!') {
207 start += 2;
208 while (start != end && *start++ != '\n');
057f943f
JF
209 }
210
b09da87b
JF
211 driver.data_ = start;
212 driver.size_ = end - start;
62ca2b82 213
b09da87b
JF
214 if (parser.parse() != 0 || !driver.errors_.empty()) {
215 for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
216 std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
217 } else if (driver.source_ != NULL) {
218 std::ostringstream str;
219 driver.source_->Show(str);
220 std::string code(str.str());
221 std::cout << code << std::endl;
222 Run(code.c_str(), stdout);
223 }
057f943f 224 }
62ca2b82 225
057f943f 226 return 0;
62ca2b82 227}