]> git.saurik.com Git - cycript.git/blame - Console.cpp
Use -fvisibility=hidden to avoid slow symbol stub.
[cycript.git] / Console.cpp
CommitLineData
b3378a02 1/* Cycript - Optimizing JavaScript Compiler/Runtime
c1d3e52e 2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
b4aa79af
JF
3*/
4
f95d2598 5/* GNU Affero General Public License, Version 3 {{{ */
b4aa79af 6/*
f95d2598
JF
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
c15969fd 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f95d2598
JF
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/>.
b3378a02 19**/
b4aa79af
JF
20/* }}} */
21
30ddc20c 22#include "cycript.hpp"
057f943f 23
9cad30fa
JF
24#ifdef CY_EXECUTE
25#include "JavaScript.hpp"
26#endif
27
057f943f 28#include <cstdio>
0df6a201 29#include <fstream>
057f943f
JF
30#include <sstream>
31
32#include <setjmp.h>
33
aff87425
DWT
34#ifdef HAVE_READLINE_H
35#include <readline.h>
36#else
057f943f 37#include <readline/readline.h>
aff87425
DWT
38#endif
39
40#ifdef HAVE_HISTORY_H
41#include <history.h>
42#else
057f943f 43#include <readline/history.h>
aff87425 44#endif
057f943f 45
b09da87b 46#include <errno.h>
10d0e915
JF
47#include <getopt.h>
48#include <signal.h>
b09da87b
JF
49#include <unistd.h>
50
666eedb9 51#include <sys/socket.h>
b09da87b
JF
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <fcntl.h>
666eedb9 55#include <netdb.h>
b09da87b 56
967067aa
JF
57#include <sys/types.h>
58#include <sys/socket.h>
59#include <netinet/in.h>
60#include <sys/un.h>
b1589845 61#include <pwd.h>
967067aa 62
da858962
JF
63#include <dlfcn.h>
64
74296173 65#include "Display.hpp"
b12a9965 66#include "Driver.hpp"
d9c91152
JF
67#include "Highlight.hpp"
68#include "Replace.hpp"
7e5391fd 69
4e39dc0b
JF
70static volatile enum {
71 Working,
72 Parsing,
73 Running,
74 Sending,
75 Waiting,
76} mode_;
77
057f943f
JF
78static jmp_buf ctrlc_;
79
579ed526 80static void sigint(int) {
4e39dc0b
JF
81 switch (mode_) {
82 case Working:
83 return;
84 case Parsing:
85 longjmp(ctrlc_, 1);
86 case Running:
b0ba908c
JF
87 CYCancel();
88 return;
4e39dc0b
JF
89 case Sending:
90 return;
91 case Waiting:
92 return;
93 }
057f943f
JF
94}
95
cac61857 96static bool bison_;
b10bd496 97static bool strict_;
11c1cc16 98static bool pretty_;
cac61857 99
d9c91152 100void Setup(CYDriver &driver) {
cac61857 101 if (bison_)
d9c91152 102 driver.debug_ = 1;
b10bd496
JF
103 if (strict_)
104 driver.strict_ = true;
cac61857
JF
105}
106
d9c91152 107void Setup(CYPool &pool, CYOutput &out, CYDriver &driver, CYOptions &options, bool lower) {
11c1cc16 108 out.pretty_ = pretty_;
36bf49c4 109 if (lower)
d9c91152 110 driver.Replace(pool, options);
11c1cc16
JF
111}
112
7e5391fd 113static CYUTF8String Run(CYPool &pool, int client, CYUTF8String code) {
967067aa 114 const char *json;
9d79cefc 115 uint32_t size;
7e5391fd 116
b166b11b 117 if (client == -1) {
4e39dc0b 118 mode_ = Running;
2aa77fd8 119#ifdef CY_EXECUTE
89d16b11 120 json = CYExecute(CYGetJSContext(), pool, code);
2aa77fd8
JF
121#else
122 json = NULL;
123#endif
4e39dc0b 124 mode_ = Working;
dd221c6b
JF
125 if (json == NULL)
126 size = 0;
127 else
6ec85c5b
JF
128 size = strlen(json);
129 } else {
4e39dc0b 130 mode_ = Sending;
0ced2e47 131 size = code.size;
a1f3555e
JF
132 _assert(CYSendAll(client, &size, sizeof(size)));
133 _assert(CYSendAll(client, code.data, code.size));
4e39dc0b 134 mode_ = Waiting;
a1f3555e 135 _assert(CYRecvAll(client, &size, sizeof(size)));
9d79cefc 136 if (size == _not(uint32_t))
967067aa
JF
137 json = NULL;
138 else {
139 char *temp(new(pool) char[size + 1]);
a1f3555e 140 _assert(CYRecvAll(client, temp, size));
967067aa
JF
141 temp[size] = '\0';
142 json = temp;
143 }
4e39dc0b 144 mode_ = Working;
4cf49641 145 }
b09da87b 146
7e5391fd
JF
147 return CYUTF8String(json, size);
148}
149
150static CYUTF8String Run(CYPool &pool, int client, const std::string &code) {
151 return Run(pool, client, CYUTF8String(code.c_str(), code.size()));
152}
153
2e2ed904 154static std::ostream *out_;
a3f4a8e1 155
82a02ede
JF
156static void Write(bool syntax, const char *data, size_t size, std::ostream &out) {
157 if (syntax)
158 CYLexerHighlight(data, size, out);
159 else
160 out.write(data, size);
161}
162
163static void Output(bool syntax, CYUTF8String json, std::ostream *out, bool expand = false) {
a3f4a8e1
JF
164 const char *data(json.data);
165 size_t size(json.size);
166
2e2ed904 167 if (data == NULL || out == NULL)
a3f4a8e1
JF
168 return;
169
0881deb5
JF
170 if (!expand ||
171 data[0] != '@' && data[0] != '"' && data[0] != '\'' ||
172 data[0] == '@' && data[1] != '"' && data[1] != '\''
173 )
82a02ede 174 Write(syntax, data, size, *out);
a3f4a8e1
JF
175 else for (size_t i(0); i != size; ++i)
176 if (data[i] != '\\')
2e2ed904 177 *out << data[i];
a3f4a8e1
JF
178 else switch(data[++i]) {
179 case '\0': goto done;
2e2ed904
JF
180 case '\\': *out << '\\'; break;
181 case '\'': *out << '\''; break;
182 case '"': *out << '"'; break;
183 case 'b': *out << '\b'; break;
184 case 'f': *out << '\f'; break;
185 case 'n': *out << '\n'; break;
186 case 'r': *out << '\r'; break;
187 case 't': *out << '\t'; break;
188 case 'v': *out << '\v'; break;
189 default: *out << '\\'; --i; break;
a3f4a8e1 190 }
6ec85c5b 191
a3f4a8e1 192 done:
2e2ed904 193 *out << std::endl;
a3f4a8e1
JF
194}
195
82a02ede 196static void Run(int client, bool syntax, const char *data, size_t size, std::ostream *out = NULL, bool expand = false) {
a3f4a8e1 197 CYPool pool;
82a02ede 198 Output(syntax, Run(pool, client, CYUTF8String(data, size)), out, expand);
b09da87b
JF
199}
200
82a02ede
JF
201static void Run(int client, bool syntax, std::string &code, std::ostream *out = NULL, bool expand = false) {
202 Run(client, syntax, code.c_str(), code.size(), out, expand);
fcc64bb5
JF
203}
204
da858962
JF
205int (*append_history$)(int, const char *);
206
7e5391fd
JF
207static std::string command_;
208
d9c91152 209static int client_;
b0385401 210
d9c91152
JF
211static CYUTF8String Run(CYPool &pool, const std::string &code) {
212 return Run(pool, client_, code);
7e5391fd
JF
213}
214
7e5391fd 215static char **Complete(const char *word, int start, int end) {
10d0e915 216 rl_attempted_completion_over = ~0;
7e5391fd 217 std::string line(rl_line_buffer, start);
d9c91152 218 return CYComplete(word, command_ + line, &Run);
7e5391fd
JF
219}
220
221// need char *, not const char *
222static char name_[] = "cycript";
87450281 223static char break_[] = " \t\n\"\\'`@><=;|&{(" ")}" ".:[]";
7e5391fd 224
da136f88
JF
225class History {
226 private:
227 std::string histfile_;
228 size_t histlines_;
229
230 public:
231 History(std::string histfile) :
232 histfile_(histfile),
233 histlines_(0)
234 {
235 read_history(histfile_.c_str());
236 }
237
238 ~History() {
239 if (append_history$ != NULL) {
f61fec22
JF
240 int fd(_syscall(open(histfile_.c_str(), O_CREAT | O_WRONLY, 0600)));
241 _syscall(close(fd));
da136f88
JF
242 _assert((*append_history$)(histlines_, histfile_.c_str()) == 0);
243 } else {
244 _assert(write_history(histfile_.c_str()) == 0);
245 }
246 }
247
248 void operator +=(const std::string &command) {
6265f0de 249 add_history(command.c_str());
da136f88
JF
250 ++histlines_;
251 }
252};
253
2eb8215d 254static void Console(CYOptions &options) {
1210260f
JF
255 std::string basedir;
256 if (const char *home = getenv("HOME"))
257 basedir = home;
258 else {
259 passwd *passwd;
260 if (const char *username = getenv("LOGNAME"))
261 passwd = getpwnam(username);
262 else
263 passwd = getpwuid(getuid());
264 basedir = passwd->pw_dir;
265 }
b1589845 266
da136f88
JF
267 basedir += "/.cycript";
268 mkdir(basedir.c_str(), 0700);
b1589845 269
7e5391fd
JF
270 rl_initialize();
271 rl_readline_name = name_;
272
da136f88 273 History history(basedir + "/history");
b1589845 274
1f8eae40
JF
275 bool bypass(false);
276 bool debug(false);
6ec85c5b 277 bool expand(false);
36bf49c4 278 bool lower(true);
cd98d280 279 bool syntax(true);
1f8eae40 280
2e2ed904 281 out_ = &std::cout;
057f943f 282
7e5391fd
JF
283 // rl_completer_word_break_characters is broken in libedit
284 rl_basic_word_break_characters = break_;
bc1e87aa
JF
285
286 rl_completer_word_break_characters = break_;
7e5391fd
JF
287 rl_attempted_completion_function = &Complete;
288 rl_bind_key('\t', rl_complete);
057f943f
JF
289
290 struct sigaction action;
291 sigemptyset(&action.sa_mask);
292 action.sa_handler = &sigint;
293 action.sa_flags = 0;
294 sigaction(SIGINT, &action, NULL);
295
296 restart: for (;;) {
7e5391fd 297 command_.clear();
057f943f
JF
298 std::vector<std::string> lines;
299
931b816a
JF
300 bool extra(false);
301 const char *prompt("cy# ");
302
057f943f 303 if (setjmp(ctrlc_) != 0) {
4e39dc0b 304 mode_ = Working;
2e2ed904 305 *out_ << std::endl;
057f943f
JF
306 goto restart;
307 }
308
057f943f 309 read:
cd98d280
JF
310
311#if RL_READLINE_VERSION >= 0x0600
8a81192b 312 if (syntax)
cd98d280 313 rl_redisplay_function = CYDisplayUpdate;
8a81192b 314 else
cd98d280 315 rl_redisplay_function = rl_redisplay;
cd98d280
JF
316#endif
317
4e39dc0b 318 mode_ = Parsing;
057f943f 319 char *line(readline(prompt));
4e39dc0b 320 mode_ = Working;
cd98d280 321
79357996
JF
322 if (line == NULL) {
323 *out_ << std::endl;
057f943f 324 break;
79357996 325 } else if (line[0] == '\0')
67f1fc6b 326 goto read;
931b816a
JF
327
328 if (!extra) {
329 extra = true;
6ec85c5b 330 if (line[0] == '?') {
1f8eae40
JF
331 std::string data(line + 1);
332 if (data == "bypass") {
333 bypass = !bypass;
2e2ed904 334 *out_ << "bypass == " << (bypass ? "true" : "false") << std::endl;
1f8eae40
JF
335 } else if (data == "debug") {
336 debug = !debug;
2e2ed904 337 *out_ << "debug == " << (debug ? "true" : "false") << std::endl;
8fab8594
JF
338 } else if (data == "destroy") {
339 CYDestroyContext();
51b6165e 340 } else if (data == "gc") {
e7ff0158 341 *out_ << "collecting... " << std::flush;
51b6165e 342 CYGarbageCollect(CYGetJSContext());
e7ff0158 343 *out_ << "done." << std::endl;
6a5fd0d9
JF
344 } else if (data == "exit") {
345 return;
6ec85c5b
JF
346 } else if (data == "expand") {
347 expand = !expand;
2e2ed904 348 *out_ << "expand == " << (expand ? "true" : "false") << std::endl;
36bf49c4
JF
349 } else if (data == "lower") {
350 lower = !lower;
351 *out_ << "lower == " << (lower ? "true" : "false") << std::endl;
82a02ede
JF
352 } else if (data == "syntax") {
353 syntax = !syntax;
354 *out_ << "syntax == " << (syntax ? "true" : "false") << std::endl;
1f8eae40 355 }
be8c2078
JF
356 command_ = line;
357 history += command_;
931b816a
JF
358 goto restart;
359 }
360 }
361
7e5391fd 362 command_ += line;
6265f0de 363 command_ += "\n";
e818f0e0
JF
364
365 char *begin(line), *end(line + strlen(line));
366 while (char *nl = reinterpret_cast<char *>(memchr(begin, '\n', end - begin))) {
367 *nl = '\0';
368 lines.push_back(begin);
369 begin = nl + 1;
370 }
371
372 lines.push_back(begin);
373
057f943f
JF
374 free(line);
375
1f8eae40
JF
376 std::string code;
377
378 if (bypass)
7e5391fd 379 code = command_;
1f8eae40 380 else {
d3b63265
JF
381 std::istringstream stream(command_);
382 CYDriver driver(stream);
d9c91152 383 Setup(driver);
d3b63265 384
d9c91152
JF
385 CYPool pool;
386 bool failed(driver.Parse(pool));
1f8eae40 387
d9c91152 388 if (failed || !driver.errors_.empty()) {
f0360d51 389 for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) {
58afc6aa 390 CYPosition begin(error->location_.begin);
6265f0de 391 if (begin.line != lines.size() + 1 || error->warning_) {
58afc6aa 392 CYPosition end(error->location_.end);
48e3be8a 393
f0360d51
JF
394 if (begin.line != lines.size()) {
395 std::cerr << " | ";
396 std::cerr << lines[begin.line - 1] << std::endl;
397 }
48e3be8a 398
c52a09b8 399 std::cerr << "....";
97c8a8fc 400 for (size_t i(0); i != begin.column; ++i)
f0360d51 401 std::cerr << '.';
48e3be8a 402 if (begin.line != end.line || begin.column == end.column)
f0360d51
JF
403 std::cerr << '^';
404 else for (size_t i(0), e(end.column - begin.column); i != e; ++i)
405 std::cerr << '^';
406 std::cerr << std::endl;
48e3be8a 407
f0360d51
JF
408 std::cerr << " | ";
409 std::cerr << error->message_ << std::endl;
48e3be8a 410
6265f0de 411 history += command_.substr(0, command_.size() - 1);
1f8eae40
JF
412 goto restart;
413 }
414 }
057f943f 415
1f8eae40 416 driver.errors_.clear();
057f943f 417
1f8eae40
JF
418 prompt = "cy> ";
419 goto read;
057f943f
JF
420 }
421
b10bd496 422 if (driver.program_ == NULL)
1f8eae40 423 goto restart;
057f943f 424
efd689d8 425 std::stringbuf str;
0df6a201 426 CYOutput out(str, options);
d9c91152 427 Setup(pool, out, driver, options, lower);
0df6a201
JF
428 out << *driver.program_;
429 code = str.str();
057f943f
JF
430 }
431
6265f0de 432 history += command_.substr(0, command_.size() - 1);
057f943f 433
82a02ede 434 if (debug) {
f43fcb85 435 std::cout << "cy= ";
82a02ede
JF
436 Write(syntax, code.c_str(), code.size(), std::cout);
437 std::cout << std::endl;
438 }
057f943f 439
82a02ede 440 Run(client_, syntax, code, out_, expand);
b09da87b 441 }
b09da87b 442}
057f943f 443
ccb4e34c 444void InjectLibrary(pid_t, int, const char *const []);
06edab7d 445
10d0e915 446int Main(int argc, char * const argv[], char const * const envp[]) {
48e3be8a 447 bool tty(isatty(STDIN_FILENO));
75b0a457 448 bool compile(false);
96746747 449 bool target(false);
de9fc71b 450 CYOptions options;
967067aa 451
e4676127 452 append_history$ = (int (*)(int, const char *)) (dlsym(RTLD_DEFAULT, "append_history"));
da858962 453
2aa77fd8
JF
454#ifdef CY_ATTACH
455 pid_t pid(_not(pid_t));
456#endif
457
666eedb9
JF
458 const char *host(NULL);
459 const char *port(NULL);
460
10d0e915 461 optind = 1;
06edab7d
JF
462
463 for (;;) {
10d0e915
JF
464 int option(getopt_long(argc, argv,
465 "c"
466 "g:"
467 "n:"
2aa77fd8 468#ifdef CY_ATTACH
10d0e915 469 "p:"
2aa77fd8 470#endif
10d0e915
JF
471 "r:"
472 "s"
f61fec22 473 , (const struct option[]) {
10d0e915
JF
474 {NULL, no_argument, NULL, 'c'},
475 {NULL, required_argument, NULL, 'g'},
476 {NULL, required_argument, NULL, 'n'},
477#ifdef CY_ATTACH
478 {NULL, required_argument, NULL, 'p'},
479#endif
480 {NULL, required_argument, NULL, 'r'},
481 {NULL, no_argument, NULL, 's'},
482 {0, 0, 0, 0}}, NULL));
06edab7d 483
10d0e915
JF
484 switch (option) {
485 case -1:
06edab7d 486 goto getopt;
10d0e915
JF
487
488 case ':':
489 case '?':
06edab7d
JF
490 fprintf(stderr,
491 "usage: cycript [-c]"
2aa77fd8 492#ifdef CY_ATTACH
69caa5be 493 " [-p <pid|name>]"
2aa77fd8 494#endif
666eedb9 495 " [-r <host:port>]"
06edab7d
JF
496 " [<script> [<arg>...]]\n"
497 );
498 return 1;
967067aa 499
96746747
JF
500 target:
501 if (!target)
502 target = true;
503 else {
504 fprintf(stderr, "only one of -[c"
505#ifdef CY_ATTACH
506 "p"
507#endif
508 "r] may be used at a time\n");
509 return 1;
510 }
511 break;
512
06edab7d
JF
513 case 'c':
514 compile = true;
96746747 515 goto target;
75b0a457 516
06edab7d
JF
517 case 'g':
518 if (false);
10d0e915 519 else if (strcmp(optarg, "rename") == 0)
de9fc71b 520 options.verbose_ = true;
10d0e915 521 else if (strcmp(optarg, "bison") == 0)
06edab7d 522 bison_ = true;
06edab7d
JF
523 else {
524 fprintf(stderr, "invalid name for -g\n");
525 return 1;
526 }
527 break;
cac61857 528
06edab7d
JF
529 case 'n':
530 if (false);
10d0e915 531 else if (strcmp(optarg, "minify") == 0)
06edab7d
JF
532 pretty_ = true;
533 else {
534 fprintf(stderr, "invalid name for -n\n");
535 return 1;
536 }
537 break;
11c1cc16 538
2aa77fd8 539#ifdef CY_ATTACH
06edab7d 540 case 'p': {
10d0e915 541 size_t size(strlen(optarg));
06edab7d 542 char *end;
69caa5be 543
10d0e915
JF
544 pid = strtoul(optarg, &end, 0);
545 if (optarg + size != end) {
69caa5be 546 // XXX: arg needs to be escaped in some horrendous way of doom
10d0e915
JF
547 // XXX: this is a memory leak now because I just don't care enough
548 char *command;
ccb4e34c
JF
549 int writ(asprintf(&command, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^%s /{s/^[^ ]* //;q;};};d'", optarg));
550 _assert(writ != -1);
69caa5be
JF
551
552 if (FILE *pids = popen(command, "r")) {
553 char value[32];
554 size = 0;
555
556 for (;;) {
557 size_t read(fread(value + size, 1, sizeof(value) - size, pids));
558 if (read == 0)
559 break;
560 else {
561 size += read;
04aa6240 562 if (size == sizeof(value))
b166b11b 563 goto fail;
69caa5be
JF
564 }
565 }
566
567 size:
568 if (size == 0)
b166b11b 569 goto fail;
69caa5be
JF
570 if (value[size - 1] == '\n') {
571 --size;
572 goto size;
573 }
574
575 value[size] = '\0';
576 size = strlen(value);
577 pid = strtoul(value, &end, 0);
b166b11b 578 if (value + size != end) fail:
69caa5be 579 pid = _not(pid_t);
69caa5be
JF
580 _syscall(pclose(pids));
581 }
582
583 if (pid == _not(pid_t)) {
10d0e915 584 fprintf(stderr, "unable to find process `%s' using ps\n", optarg);
69caa5be
JF
585 return 1;
586 }
06edab7d 587 }
96746747 588 } goto target;
2aa77fd8 589#endif
b10bd496 590
666eedb9 591 case 'r': {
10d0e915 592 //size_t size(strlen(optarg));
666eedb9 593
10d0e915 594 char *colon(strrchr(optarg, ':'));
666eedb9
JF
595 if (colon == NULL) {
596 fprintf(stderr, "missing colon in hostspec\n");
597 return 1;
598 }
599
600 /*char *end;
601 port = strtoul(colon + 1, &end, 10);
10d0e915 602 if (end != optarg + size) {
666eedb9
JF
603 fprintf(stderr, "invalid port in hostspec\n");
604 return 1;
605 }*/
606
10d0e915 607 host = optarg;
666eedb9
JF
608 *colon = '\0';
609 port = colon + 1;
96746747 610 } goto target;
666eedb9 611
06edab7d
JF
612 case 's':
613 strict_ = true;
614 break;
10d0e915
JF
615
616 default:
617 _assert(false);
06edab7d 618 }
10d0e915
JF
619 }
620
621 getopt:
622 argc -= optind;
623 argv += optind;
967067aa 624
b09da87b
JF
625 const char *script;
626
2aa77fd8 627#ifdef CY_ATTACH
10d0e915 628 if (pid != _not(pid_t) && argc > 1) {
fcc64bb5
JF
629 fprintf(stderr, "-p cannot set argv\n");
630 return 1;
631 }
2aa77fd8 632#endif
75b0a457 633
10d0e915 634 if (argc == 0)
b09da87b
JF
635 script = NULL;
636 else {
9185d5ef 637#ifdef CY_EXECUTE
967067aa 638 // XXX: const_cast?! wtf gcc :(
10d0e915 639 CYSetArgs(argc - 1, const_cast<const char **>(argv + 1));
9185d5ef 640#endif
10d0e915 641 script = argv[0];
967067aa
JF
642 if (strcmp(script, "-") == 0)
643 script = NULL;
b09da87b
JF
644 }
645
2aa77fd8 646#ifdef CY_ATTACH
967067aa 647 if (pid == _not(pid_t))
7e5391fd 648 client_ = -1;
967067aa 649 else {
46d13f4c
JF
650 struct Socket {
651 int fd_;
b166b11b 652
46d13f4c
JF
653 Socket(int fd) :
654 fd_(fd)
655 {
656 }
96cc7967 657
46d13f4c
JF
658 ~Socket() {
659 close(fd_);
660 }
96cc7967 661
46d13f4c
JF
662 operator int() {
663 return fd_;
664 }
665 } server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0)));
96cc7967 666
46d13f4c
JF
667 struct sockaddr_un address;
668 memset(&address, 0, sizeof(address));
669 address.sun_family = AF_UNIX;
b166b11b 670
f8d45a20
JF
671 const char *tmp;
672#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
673 tmp = "/Library/Caches";
674#else
675 tmp = "/tmp";
676#endif
677
678 sprintf(address.sun_path, "%s/.s.cy.%u", tmp, getpid());
46d13f4c 679 unlink(address.sun_path);
b166b11b 680
46d13f4c
JF
681 struct File {
682 const char *path_;
683
684 File(const char *path) :
685 path_(path)
686 {
687 }
688
689 ~File() {
690 unlink(path_);
691 }
692 } file(address.sun_path);
693
694 _syscall(bind(server, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
695 _syscall(chmod(address.sun_path, 0777));
696
697 _syscall(listen(server, 1));
ccb4e34c
JF
698 const char *const argv[] = {address.sun_path, NULL};
699 InjectLibrary(pid, 1, argv);
46d13f4c 700 client_ = _syscall(accept(server, NULL, NULL));
967067aa 701 }
2aa77fd8 702#else
7e5391fd 703 client_ = -1;
2aa77fd8 704#endif
579ed526 705
666eedb9
JF
706 if (client_ == -1 && host != NULL && port != NULL) {
707 struct addrinfo hints;
708 memset(&hints, 0, sizeof(hints));
709 hints.ai_family = AF_UNSPEC;
710 hints.ai_socktype = SOCK_STREAM;
711 hints.ai_protocol = 0;
712 hints.ai_flags = 0;
713
714 struct addrinfo *infos;
715 _syscall(getaddrinfo(host, port, &hints, &infos));
716
717 _assert(infos != NULL); try {
718 for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) {
719 int client(_syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol))); try {
720 _syscall(connect(client, info->ai_addr, info->ai_addrlen));
721 client_ = client;
722 break;
723 } catch (...) {
724 _syscall(close(client));
725 throw;
726 }
727 }
728 } catch (...) {
729 freeaddrinfo(infos);
730 throw;
731 }
732 }
733
48e3be8a 734 if (script == NULL && tty)
2eb8215d 735 Console(options);
b09da87b 736 else {
0df6a201 737 std::istream *stream;
48e3be8a 738 if (script == NULL) {
0df6a201
JF
739 stream = &std::cin;
740 script = "<stdin>";
48e3be8a 741 } else {
0df6a201
JF
742 stream = new std::fstream(script, std::ios::in | std::ios::binary);
743 _assert(!stream->fail());
48e3be8a 744 }
62ca2b82 745
0df6a201 746 CYDriver driver(*stream, script);
d9c91152
JF
747 Setup(driver);
748
749 CYPool pool;
750 bool failed(driver.Parse(pool));
d3b63265 751
d9c91152 752 if (failed || !driver.errors_.empty()) {
b09da87b
JF
753 for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
754 std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
0df6a201 755 } else if (driver.program_ != NULL) {
efd689d8 756 std::stringbuf str;
0df6a201 757 CYOutput out(str, options);
d9c91152 758 Setup(pool, out, driver, options, true);
0df6a201
JF
759 out << *driver.program_;
760 std::string code(str.str());
761 if (compile)
762 std::cout << code;
763 else
82a02ede 764 Run(client_, false, code, &std::cout);
0df6a201 765 }
057f943f 766 }
62ca2b82 767
057f943f 768 return 0;
62ca2b82 769}
b6961e53 770
10d0e915
JF
771int main(int argc, char * const argv[], char const * const envp[]) {
772 try {
b6961e53
JF
773 return Main(argc, argv, envp);
774 } catch (const CYException &error) {
775 CYPool pool;
776 fprintf(stderr, "%s\n", error.PoolCString(pool));
777 return 1;
778 }
779}