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