]> git.saurik.com Git - cycript.git/blame - Console.cpp
Remove flex/gperf hacks (this was fixed upstream).
[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
2c1d569a 107void Setup(CYOutput &out, CYDriver &driver, CYOptions &options, bool lower) {
11c1cc16 108 out.pretty_ = pretty_;
36bf49c4 109 if (lower)
2c1d569a 110 driver.Replace(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 381 std::istringstream stream(command_);
d3b63265 382
d9c91152 383 CYPool pool;
2c1d569a
JF
384 CYDriver driver(pool, stream);
385 Setup(driver);
386
387 bool failed(driver.Parse());
1f8eae40 388
d9c91152 389 if (failed || !driver.errors_.empty()) {
f0360d51 390 for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) {
58afc6aa 391 CYPosition begin(error->location_.begin);
6265f0de 392 if (begin.line != lines.size() + 1 || error->warning_) {
58afc6aa 393 CYPosition end(error->location_.end);
48e3be8a 394
f0360d51
JF
395 if (begin.line != lines.size()) {
396 std::cerr << " | ";
397 std::cerr << lines[begin.line - 1] << std::endl;
398 }
48e3be8a 399
c52a09b8 400 std::cerr << "....";
97c8a8fc 401 for (size_t i(0); i != begin.column; ++i)
f0360d51 402 std::cerr << '.';
48e3be8a 403 if (begin.line != end.line || begin.column == end.column)
f0360d51
JF
404 std::cerr << '^';
405 else for (size_t i(0), e(end.column - begin.column); i != e; ++i)
406 std::cerr << '^';
407 std::cerr << std::endl;
48e3be8a 408
f0360d51
JF
409 std::cerr << " | ";
410 std::cerr << error->message_ << std::endl;
48e3be8a 411
6265f0de 412 history += command_.substr(0, command_.size() - 1);
1f8eae40
JF
413 goto restart;
414 }
415 }
057f943f 416
1f8eae40 417 driver.errors_.clear();
057f943f 418
1f8eae40
JF
419 prompt = "cy> ";
420 goto read;
057f943f
JF
421 }
422
b10bd496 423 if (driver.program_ == NULL)
1f8eae40 424 goto restart;
057f943f 425
efd689d8 426 std::stringbuf str;
0df6a201 427 CYOutput out(str, options);
2c1d569a 428 Setup(out, driver, options, lower);
0df6a201
JF
429 out << *driver.program_;
430 code = str.str();
057f943f
JF
431 }
432
6265f0de 433 history += command_.substr(0, command_.size() - 1);
057f943f 434
82a02ede 435 if (debug) {
f43fcb85 436 std::cout << "cy= ";
82a02ede
JF
437 Write(syntax, code.c_str(), code.size(), std::cout);
438 std::cout << std::endl;
439 }
057f943f 440
82a02ede 441 Run(client_, syntax, code, out_, expand);
b09da87b 442 }
b09da87b 443}
057f943f 444
ccb4e34c 445void InjectLibrary(pid_t, int, const char *const []);
06edab7d 446
10d0e915 447int Main(int argc, char * const argv[], char const * const envp[]) {
48e3be8a 448 bool tty(isatty(STDIN_FILENO));
75b0a457 449 bool compile(false);
96746747 450 bool target(false);
de9fc71b 451 CYOptions options;
967067aa 452
e4676127 453 append_history$ = (int (*)(int, const char *)) (dlsym(RTLD_DEFAULT, "append_history"));
da858962 454
2aa77fd8
JF
455#ifdef CY_ATTACH
456 pid_t pid(_not(pid_t));
457#endif
458
666eedb9
JF
459 const char *host(NULL);
460 const char *port(NULL);
461
10d0e915 462 optind = 1;
06edab7d
JF
463
464 for (;;) {
10d0e915
JF
465 int option(getopt_long(argc, argv,
466 "c"
467 "g:"
468 "n:"
2aa77fd8 469#ifdef CY_ATTACH
10d0e915 470 "p:"
2aa77fd8 471#endif
10d0e915
JF
472 "r:"
473 "s"
f61fec22 474 , (const struct option[]) {
10d0e915
JF
475 {NULL, no_argument, NULL, 'c'},
476 {NULL, required_argument, NULL, 'g'},
477 {NULL, required_argument, NULL, 'n'},
478#ifdef CY_ATTACH
479 {NULL, required_argument, NULL, 'p'},
480#endif
481 {NULL, required_argument, NULL, 'r'},
482 {NULL, no_argument, NULL, 's'},
483 {0, 0, 0, 0}}, NULL));
06edab7d 484
10d0e915
JF
485 switch (option) {
486 case -1:
06edab7d 487 goto getopt;
10d0e915
JF
488
489 case ':':
490 case '?':
06edab7d
JF
491 fprintf(stderr,
492 "usage: cycript [-c]"
2aa77fd8 493#ifdef CY_ATTACH
69caa5be 494 " [-p <pid|name>]"
2aa77fd8 495#endif
666eedb9 496 " [-r <host:port>]"
06edab7d
JF
497 " [<script> [<arg>...]]\n"
498 );
499 return 1;
967067aa 500
96746747
JF
501 target:
502 if (!target)
503 target = true;
504 else {
505 fprintf(stderr, "only one of -[c"
506#ifdef CY_ATTACH
507 "p"
508#endif
509 "r] may be used at a time\n");
510 return 1;
511 }
512 break;
513
06edab7d
JF
514 case 'c':
515 compile = true;
96746747 516 goto target;
75b0a457 517
06edab7d
JF
518 case 'g':
519 if (false);
10d0e915 520 else if (strcmp(optarg, "rename") == 0)
de9fc71b 521 options.verbose_ = true;
10d0e915 522 else if (strcmp(optarg, "bison") == 0)
06edab7d 523 bison_ = true;
06edab7d
JF
524 else {
525 fprintf(stderr, "invalid name for -g\n");
526 return 1;
527 }
528 break;
cac61857 529
06edab7d
JF
530 case 'n':
531 if (false);
10d0e915 532 else if (strcmp(optarg, "minify") == 0)
06edab7d
JF
533 pretty_ = true;
534 else {
535 fprintf(stderr, "invalid name for -n\n");
536 return 1;
537 }
538 break;
11c1cc16 539
2aa77fd8 540#ifdef CY_ATTACH
06edab7d 541 case 'p': {
10d0e915 542 size_t size(strlen(optarg));
06edab7d 543 char *end;
69caa5be 544
10d0e915
JF
545 pid = strtoul(optarg, &end, 0);
546 if (optarg + size != end) {
69caa5be 547 // XXX: arg needs to be escaped in some horrendous way of doom
10d0e915
JF
548 // XXX: this is a memory leak now because I just don't care enough
549 char *command;
ccb4e34c
JF
550 int writ(asprintf(&command, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^%s /{s/^[^ ]* //;q;};};d'", optarg));
551 _assert(writ != -1);
69caa5be
JF
552
553 if (FILE *pids = popen(command, "r")) {
554 char value[32];
555 size = 0;
556
557 for (;;) {
558 size_t read(fread(value + size, 1, sizeof(value) - size, pids));
559 if (read == 0)
560 break;
561 else {
562 size += read;
04aa6240 563 if (size == sizeof(value))
b166b11b 564 goto fail;
69caa5be
JF
565 }
566 }
567
568 size:
569 if (size == 0)
b166b11b 570 goto fail;
69caa5be
JF
571 if (value[size - 1] == '\n') {
572 --size;
573 goto size;
574 }
575
576 value[size] = '\0';
577 size = strlen(value);
578 pid = strtoul(value, &end, 0);
b166b11b 579 if (value + size != end) fail:
69caa5be 580 pid = _not(pid_t);
69caa5be
JF
581 _syscall(pclose(pids));
582 }
583
584 if (pid == _not(pid_t)) {
10d0e915 585 fprintf(stderr, "unable to find process `%s' using ps\n", optarg);
69caa5be
JF
586 return 1;
587 }
06edab7d 588 }
96746747 589 } goto target;
2aa77fd8 590#endif
b10bd496 591
666eedb9 592 case 'r': {
10d0e915 593 //size_t size(strlen(optarg));
666eedb9 594
10d0e915 595 char *colon(strrchr(optarg, ':'));
666eedb9
JF
596 if (colon == NULL) {
597 fprintf(stderr, "missing colon in hostspec\n");
598 return 1;
599 }
600
601 /*char *end;
602 port = strtoul(colon + 1, &end, 10);
10d0e915 603 if (end != optarg + size) {
666eedb9
JF
604 fprintf(stderr, "invalid port in hostspec\n");
605 return 1;
606 }*/
607
10d0e915 608 host = optarg;
666eedb9
JF
609 *colon = '\0';
610 port = colon + 1;
96746747 611 } goto target;
666eedb9 612
06edab7d
JF
613 case 's':
614 strict_ = true;
615 break;
10d0e915
JF
616
617 default:
618 _assert(false);
06edab7d 619 }
10d0e915
JF
620 }
621
622 getopt:
623 argc -= optind;
624 argv += optind;
967067aa 625
b09da87b
JF
626 const char *script;
627
2aa77fd8 628#ifdef CY_ATTACH
10d0e915 629 if (pid != _not(pid_t) && argc > 1) {
fcc64bb5
JF
630 fprintf(stderr, "-p cannot set argv\n");
631 return 1;
632 }
2aa77fd8 633#endif
75b0a457 634
10d0e915 635 if (argc == 0)
b09da87b
JF
636 script = NULL;
637 else {
9185d5ef 638#ifdef CY_EXECUTE
967067aa 639 // XXX: const_cast?! wtf gcc :(
10d0e915 640 CYSetArgs(argc - 1, const_cast<const char **>(argv + 1));
9185d5ef 641#endif
10d0e915 642 script = argv[0];
967067aa
JF
643 if (strcmp(script, "-") == 0)
644 script = NULL;
b09da87b
JF
645 }
646
2aa77fd8 647#ifdef CY_ATTACH
967067aa 648 if (pid == _not(pid_t))
7e5391fd 649 client_ = -1;
967067aa 650 else {
46d13f4c
JF
651 struct Socket {
652 int fd_;
b166b11b 653
46d13f4c
JF
654 Socket(int fd) :
655 fd_(fd)
656 {
657 }
96cc7967 658
46d13f4c
JF
659 ~Socket() {
660 close(fd_);
661 }
96cc7967 662
46d13f4c
JF
663 operator int() {
664 return fd_;
665 }
666 } server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0)));
96cc7967 667
46d13f4c
JF
668 struct sockaddr_un address;
669 memset(&address, 0, sizeof(address));
670 address.sun_family = AF_UNIX;
b166b11b 671
f8d45a20
JF
672 const char *tmp;
673#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
674 tmp = "/Library/Caches";
675#else
676 tmp = "/tmp";
677#endif
678
679 sprintf(address.sun_path, "%s/.s.cy.%u", tmp, getpid());
46d13f4c 680 unlink(address.sun_path);
b166b11b 681
46d13f4c
JF
682 struct File {
683 const char *path_;
684
685 File(const char *path) :
686 path_(path)
687 {
688 }
689
690 ~File() {
691 unlink(path_);
692 }
693 } file(address.sun_path);
694
695 _syscall(bind(server, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
696 _syscall(chmod(address.sun_path, 0777));
697
698 _syscall(listen(server, 1));
ccb4e34c
JF
699 const char *const argv[] = {address.sun_path, NULL};
700 InjectLibrary(pid, 1, argv);
46d13f4c 701 client_ = _syscall(accept(server, NULL, NULL));
967067aa 702 }
2aa77fd8 703#else
7e5391fd 704 client_ = -1;
2aa77fd8 705#endif
579ed526 706
666eedb9
JF
707 if (client_ == -1 && host != NULL && port != NULL) {
708 struct addrinfo hints;
709 memset(&hints, 0, sizeof(hints));
710 hints.ai_family = AF_UNSPEC;
711 hints.ai_socktype = SOCK_STREAM;
712 hints.ai_protocol = 0;
713 hints.ai_flags = 0;
714
715 struct addrinfo *infos;
716 _syscall(getaddrinfo(host, port, &hints, &infos));
717
718 _assert(infos != NULL); try {
719 for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) {
720 int client(_syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol))); try {
721 _syscall(connect(client, info->ai_addr, info->ai_addrlen));
722 client_ = client;
723 break;
724 } catch (...) {
725 _syscall(close(client));
726 throw;
727 }
728 }
729 } catch (...) {
730 freeaddrinfo(infos);
731 throw;
732 }
733 }
734
48e3be8a 735 if (script == NULL && tty)
2eb8215d 736 Console(options);
b09da87b 737 else {
0df6a201 738 std::istream *stream;
48e3be8a 739 if (script == NULL) {
0df6a201
JF
740 stream = &std::cin;
741 script = "<stdin>";
48e3be8a 742 } else {
0df6a201
JF
743 stream = new std::fstream(script, std::ios::in | std::ios::binary);
744 _assert(!stream->fail());
48e3be8a 745 }
62ca2b82 746
2c1d569a
JF
747 CYPool pool;
748 CYDriver driver(pool, *stream, script);
d9c91152
JF
749 Setup(driver);
750
2c1d569a 751 bool failed(driver.Parse());
d3b63265 752
d9c91152 753 if (failed || !driver.errors_.empty()) {
b09da87b
JF
754 for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
755 std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
0df6a201 756 } else if (driver.program_ != NULL) {
efd689d8 757 std::stringbuf str;
0df6a201 758 CYOutput out(str, options);
2c1d569a 759 Setup(out, driver, options, true);
0df6a201
JF
760 out << *driver.program_;
761 std::string code(str.str());
762 if (compile)
763 std::cout << code;
764 else
82a02ede 765 Run(client_, false, code, &std::cout);
0df6a201 766 }
057f943f 767 }
62ca2b82 768
057f943f 769 return 0;
62ca2b82 770}
b6961e53 771
10d0e915
JF
772int main(int argc, char * const argv[], char const * const envp[]) {
773 try {
b6961e53
JF
774 return Main(argc, argv, envp);
775 } catch (const CYException &error) {
776 CYPool pool;
777 fprintf(stderr, "%s\n", error.PoolCString(pool));
778 return 1;
779 }
780}