]> git.saurik.com Git - cycript.git/blame - Console.cpp
Commit the large accumulation of todo.txt changes.
[cycript.git] / Console.cpp
CommitLineData
b3378a02 1/* Cycript - Optimizing JavaScript Compiler/Runtime
8d7447c1 2 * Copyright (C) 2009-2012 Jay Freeman (saurik)
b4aa79af
JF
3*/
4
b3378a02 5/* GNU Lesser General Public License, Version 3 {{{ */
b4aa79af 6/*
b3378a02
JF
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.
b4aa79af 11 *
b3378a02
JF
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.
b4aa79af 16 *
b3378a02
JF
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**/
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
JF
28#include <cstdio>
29#include <sstream>
30
31#include <setjmp.h>
32
aff87425
DWT
33#ifdef HAVE_READLINE_H
34#include <readline.h>
35#else
057f943f 36#include <readline/readline.h>
aff87425
DWT
37#endif
38
39#ifdef HAVE_HISTORY_H
40#include <history.h>
41#else
057f943f 42#include <readline/history.h>
aff87425 43#endif
057f943f 44
b09da87b
JF
45#include <sys/mman.h>
46
47#include <errno.h>
48#include <unistd.h>
49
50#include <sys/types.h>
51#include <sys/stat.h>
52#include <fcntl.h>
53
057f943f
JF
54#include "Cycript.tab.hh"
55
967067aa
JF
56#include <sys/types.h>
57#include <sys/socket.h>
58#include <netinet/in.h>
59#include <sys/un.h>
b1589845 60#include <pwd.h>
967067aa 61
06edab7d
JF
62#include <apr_getopt.h>
63
da858962
JF
64#include <dlfcn.h>
65
7e5391fd
JF
66#include "Replace.hpp"
67
4e39dc0b
JF
68static volatile enum {
69 Working,
70 Parsing,
71 Running,
72 Sending,
73 Waiting,
74} mode_;
75
057f943f
JF
76static jmp_buf ctrlc_;
77
579ed526 78static void sigint(int) {
4e39dc0b
JF
79 switch (mode_) {
80 case Working:
81 return;
82 case Parsing:
83 longjmp(ctrlc_, 1);
84 case Running:
85 throw "*** Ctrl-C";
86 case Sending:
87 return;
88 case Waiting:
89 return;
90 }
057f943f
JF
91}
92
cac61857
JF
93#if YYDEBUG
94static bool bison_;
95#endif
b10bd496 96static bool strict_;
11c1cc16 97static bool pretty_;
cac61857 98
b10bd496 99void Setup(CYDriver &driver, cy::parser &parser) {
cac61857
JF
100#if YYDEBUG
101 if (bison_)
102 parser.set_debug_level(1);
103#endif
b10bd496
JF
104 if (strict_)
105 driver.strict_ = true;
cac61857
JF
106}
107
de9fc71b 108void Setup(CYOutput &out, CYDriver &driver, CYOptions &options) {
11c1cc16 109 out.pretty_ = pretty_;
2eb8215d 110 CYContext context(options);
3b52fd1a 111 driver.program_->Replace(context);
11c1cc16
JF
112}
113
7e5391fd 114static CYUTF8String Run(CYPool &pool, int client, CYUTF8String code) {
967067aa 115 const char *json;
7e5391fd
JF
116 size_t size;
117
b166b11b 118 if (client == -1) {
4e39dc0b 119 mode_ = Running;
2aa77fd8 120#ifdef CY_EXECUTE
0ced2e47 121 json = CYExecute(pool, code);
2aa77fd8
JF
122#else
123 json = NULL;
124#endif
4e39dc0b 125 mode_ = Working;
dd221c6b
JF
126 if (json == NULL)
127 size = 0;
128 else
6ec85c5b
JF
129 size = strlen(json);
130 } else {
4e39dc0b 131 mode_ = Sending;
0ced2e47 132 size = code.size;
b166b11b 133 CYSendAll(client, &size, sizeof(size));
0ced2e47 134 CYSendAll(client, code.data, code.size);
4e39dc0b 135 mode_ = Waiting;
b166b11b 136 CYRecvAll(client, &size, sizeof(size));
967067aa
JF
137 if (size == _not(size_t))
138 json = NULL;
139 else {
140 char *temp(new(pool) char[size + 1]);
b166b11b 141 CYRecvAll(client, temp, size);
967067aa
JF
142 temp[size] = '\0';
143 json = temp;
144 }
4e39dc0b 145 mode_ = Working;
4cf49641 146 }
b09da87b 147
7e5391fd
JF
148 return CYUTF8String(json, size);
149}
150
151static CYUTF8String Run(CYPool &pool, int client, const std::string &code) {
152 return Run(pool, client, CYUTF8String(code.c_str(), code.size()));
153}
154
a3f4a8e1
JF
155FILE *fout_;
156
157static void Output(CYUTF8String json, FILE *fout, bool expand = false) {
158 const char *data(json.data);
159 size_t size(json.size);
160
161 if (data == NULL || fout == NULL)
162 return;
163
0881deb5
JF
164 if (!expand ||
165 data[0] != '@' && data[0] != '"' && data[0] != '\'' ||
166 data[0] == '@' && data[1] != '"' && data[1] != '\''
167 )
a3f4a8e1
JF
168 fputs(data, fout);
169 else for (size_t i(0); i != size; ++i)
170 if (data[i] != '\\')
171 fputc(data[i], fout);
172 else switch(data[++i]) {
173 case '\0': goto done;
174 case '\\': fputc('\\', fout); break;
175 case '\'': fputc('\'', fout); break;
176 case '"': fputc('"', fout); break;
177 case 'b': fputc('\b', fout); break;
178 case 'f': fputc('\f', fout); break;
179 case 'n': fputc('\n', fout); break;
180 case 'r': fputc('\r', fout); break;
181 case 't': fputc('\t', fout); break;
182 case 'v': fputc('\v', fout); break;
183 default: fputc('\\', fout); --i; break;
184 }
6ec85c5b 185
a3f4a8e1
JF
186 done:
187 fputs("\n", fout);
188 fflush(fout);
189}
190
191static void Run(int client, const char *data, size_t size, FILE *fout = NULL, bool expand = false) {
192 CYPool pool;
193 Output(Run(pool, client, CYUTF8String(data, size)), fout, expand);
b09da87b
JF
194}
195
7e5391fd 196static void Run(int client, std::string &code, FILE *fout = NULL, bool expand = false) {
b166b11b 197 Run(client, code.c_str(), code.size(), fout, expand);
fcc64bb5
JF
198}
199
da858962
JF
200int (*append_history$)(int, const char *);
201
7e5391fd
JF
202static std::string command_;
203
2eb8215d 204static CYExpression *ParseExpression(CYUTF8String code) {
7e5391fd
JF
205 std::ostringstream str;
206 str << '(' << code << ')';
207 std::string string(str.str());
208
2eb8215d 209 CYDriver driver;
7e5391fd
JF
210 driver.data_ = string.c_str();
211 driver.size_ = string.size();
212
213 cy::parser parser(driver);
214 Setup(driver, parser);
215
216 if (parser.parse() != 0 || !driver.errors_.empty())
df24434f 217 return NULL;
7e5391fd 218
e06e5ee1
JF
219 CYOptions options;
220 CYContext context(options);
221
222 // XXX: this could be replaced with a CYStatement::Primitive()
223 if (CYExpress *express = dynamic_cast<CYExpress *>(driver.program_->statements_))
224 return express->expression_->Primitive(context);
225
226 return NULL;
7e5391fd
JF
227}
228
229static int client_;
230
231static char **Complete(const char *word, int start, int end) {
232 rl_attempted_completion_over = TRUE;
233
2eb8215d
JF
234 CYLocalPool pool;
235 CYDriver driver;
7e5391fd
JF
236 cy::parser parser(driver);
237 Setup(driver, parser);
238
239 std::string line(rl_line_buffer, start);
240 std::string command(command_ + line);
241
242 driver.data_ = command.c_str();
243 driver.size_ = command.size();
244
245 driver.auto_ = true;
246
247 if (parser.parse() != 0 || !driver.errors_.empty())
248 return NULL;
249
250 if (driver.mode_ == CYDriver::AutoNone)
251 return NULL;
252
253 CYExpression *expression;
254
255 CYOptions options;
2eb8215d 256 CYContext context(options);
7e5391fd
JF
257
258 std::ostringstream prefix;
259
260 switch (driver.mode_) {
261 case CYDriver::AutoPrimary:
262 expression = $ CYThis();
263 break;
264
265 case CYDriver::AutoDirect:
266 expression = driver.context_;
267 break;
268
269 case CYDriver::AutoIndirect:
270 expression = $ CYIndirect(driver.context_);
271 break;
272
273 case CYDriver::AutoMessage: {
274 CYDriver::Context &thing(driver.contexts_.back());
aa926c8b 275 expression = $M($C1($V("object_getClass"), thing.context_), $S("messages"));
7e5391fd
JF
276 for (CYDriver::Context::Words::const_iterator part(thing.words_.begin()); part != thing.words_.end(); ++part)
277 prefix << (*part)->word_ << ':';
278 } break;
279
280 default:
281 _assert(false);
282 }
283
2a18313c 284 std::string begin(prefix.str());
7e5391fd 285
2eb8215d 286 driver.program_ = $ CYProgram($ CYExpress($C3(ParseExpression(
2a18313c 287 " function(object, prefix, word) {\n"
7e5391fd 288 " var names = [];\n"
5a3f7a01
JF
289 " var before = prefix.length;\n"
290 " prefix += word;\n"
291 " var entire = prefix.length;\n"
7e5391fd 292 " for (name in object)\n"
5a3f7a01
JF
293 " if (name.substring(0, entire) == prefix)\n"
294 " names.push(name.substr(before));\n"
7e5391fd
JF
295 " return names;\n"
296 " }\n"
2a18313c 297 ), expression, $S(begin.c_str()), $S(word))));
7e5391fd
JF
298
299 driver.program_->Replace(context);
300
301 std::ostringstream str;
302 CYOutput out(str, options);
303 out << *driver.program_;
304
305 std::string code(str.str());
306 CYUTF8String json(Run(pool, client_, code));
1b2613d3 307 // XXX: if this fails we should not try to parse it
7e5391fd 308
2eb8215d 309 CYExpression *result(ParseExpression(json));
df24434f
JF
310 if (result == NULL)
311 return NULL;
312
7e5391fd 313 CYArray *array(dynamic_cast<CYArray *>(result));
a3f4a8e1
JF
314
315 if (array == NULL) {
316 fprintf(fout_, "\n");
317 Output(json, fout_);
318 rl_forced_update_display();
319 return NULL;
320 }
7e5391fd
JF
321
322 // XXX: use an std::set?
323 typedef std::vector<std::string> Completions;
324 Completions completions;
325
326 std::string common;
327 bool rest(false);
328
c2c9f509 329 CYForEach (element, array->elements_) {
7e5391fd
JF
330 CYString *string(dynamic_cast<CYString *>(element->value_));
331 _assert(string != NULL);
332
763aa499
JF
333 std::string completion;
334 if (string->size_ != 0)
335 completion.assign(string->value_, string->size_);
336 else if (driver.mode_ == CYDriver::AutoMessage)
337 completion = "]";
338 else
339 continue;
340
7e5391fd
JF
341 completions.push_back(completion);
342
343 if (!rest) {
344 common = completion;
345 rest = true;
346 } else {
347 size_t limit(completion.size()), size(common.size());
348 if (size > limit)
349 common = common.substr(0, limit);
350 else
351 limit = size;
352 for (limit = 0; limit != size; ++limit)
353 if (common[limit] != completion[limit])
354 break;
355 if (limit != size)
356 common = common.substr(0, limit);
357 }
358 }
359
360 size_t count(completions.size());
361 if (count == 0)
362 return NULL;
363
c41590b2
JF
364 size_t colon(common.find(':'));
365 if (colon != std::string::npos)
366 common = common.substr(0, colon + 1);
6dccefa9
JF
367 if (completions.size() == 1)
368 common += ' ';
c41590b2 369
7e5391fd
JF
370 char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count + 2))));
371
372 results[0] = strdup(common.c_str());
373 size_t index(0);
374 for (Completions::const_iterator i(completions.begin()); i != completions.end(); ++i)
375 results[++index] = strdup(i->c_str());
376 results[count + 1] = NULL;
377
378 return results;
379}
380
381// need char *, not const char *
382static char name_[] = "cycript";
108c5fc8 383static char break_[] = " \t\n\"\\'`@$><=;|&{(" ")}" ".:[]";
7e5391fd 384
2eb8215d
JF
385static void Console(CYOptions &options) {
386 CYPool pool;
387
b1589845
JF
388 passwd *passwd;
389 if (const char *username = getenv("LOGNAME"))
390 passwd = getpwnam(username);
391 else
392 passwd = getpwuid(getuid());
393
394 const char *basedir(apr_psprintf(pool, "%s/.cycript", passwd->pw_dir));
395 const char *histfile(apr_psprintf(pool, "%s/history", basedir));
396 size_t histlines(0);
397
7e5391fd
JF
398 rl_initialize();
399 rl_readline_name = name_;
400
b1589845
JF
401 mkdir(basedir, 0700);
402 read_history(histfile);
403
1f8eae40
JF
404 bool bypass(false);
405 bool debug(false);
6ec85c5b 406 bool expand(false);
1f8eae40 407
a3f4a8e1 408 fout_ = stdout;
057f943f 409
7e5391fd
JF
410 // rl_completer_word_break_characters is broken in libedit
411 rl_basic_word_break_characters = break_;
bc1e87aa
JF
412
413 rl_completer_word_break_characters = break_;
7e5391fd
JF
414 rl_attempted_completion_function = &Complete;
415 rl_bind_key('\t', rl_complete);
057f943f
JF
416
417 struct sigaction action;
418 sigemptyset(&action.sa_mask);
419 action.sa_handler = &sigint;
420 action.sa_flags = 0;
421 sigaction(SIGINT, &action, NULL);
422
423 restart: for (;;) {
7e5391fd 424 command_.clear();
057f943f
JF
425 std::vector<std::string> lines;
426
931b816a
JF
427 bool extra(false);
428 const char *prompt("cy# ");
429
057f943f 430 if (setjmp(ctrlc_) != 0) {
4e39dc0b 431 mode_ = Working;
a3f4a8e1
JF
432 fputs("\n", fout_);
433 fflush(fout_);
057f943f
JF
434 goto restart;
435 }
436
057f943f 437 read:
4e39dc0b 438 mode_ = Parsing;
057f943f 439 char *line(readline(prompt));
4e39dc0b 440 mode_ = Working;
057f943f
JF
441 if (line == NULL)
442 break;
67f1fc6b
JF
443 if (line[0] == '\0')
444 goto read;
931b816a
JF
445
446 if (!extra) {
447 extra = true;
6ec85c5b 448 if (line[0] == '?') {
1f8eae40
JF
449 std::string data(line + 1);
450 if (data == "bypass") {
451 bypass = !bypass;
a3f4a8e1
JF
452 fprintf(fout_, "bypass == %s\n", bypass ? "true" : "false");
453 fflush(fout_);
1f8eae40
JF
454 } else if (data == "debug") {
455 debug = !debug;
a3f4a8e1
JF
456 fprintf(fout_, "debug == %s\n", debug ? "true" : "false");
457 fflush(fout_);
6ec85c5b
JF
458 } else if (data == "expand") {
459 expand = !expand;
a3f4a8e1
JF
460 fprintf(fout_, "expand == %s\n", expand ? "true" : "false");
461 fflush(fout_);
1f8eae40 462 }
d35a3b07 463 add_history(line);
b1589845 464 ++histlines;
931b816a
JF
465 goto restart;
466 }
467 }
468
7e5391fd 469 command_ += line;
e818f0e0
JF
470
471 char *begin(line), *end(line + strlen(line));
472 while (char *nl = reinterpret_cast<char *>(memchr(begin, '\n', end - begin))) {
473 *nl = '\0';
474 lines.push_back(begin);
475 begin = nl + 1;
476 }
477
478 lines.push_back(begin);
479
057f943f
JF
480 free(line);
481
1f8eae40
JF
482 std::string code;
483
484 if (bypass)
7e5391fd 485 code = command_;
1f8eae40 486 else {
2eb8215d 487 CYLocalPool pool;
7e5391fd 488 CYDriver driver;
1f8eae40 489 cy::parser parser(driver);
b10bd496 490 Setup(driver, parser);
1f8eae40 491
7e5391fd
JF
492 driver.data_ = command_.c_str();
493 driver.size_ = command_.size();
1f8eae40
JF
494
495 if (parser.parse() != 0 || !driver.errors_.empty()) {
f0360d51
JF
496 for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) {
497 cy::position begin(error->location_.begin);
c247172c 498 if (begin.line != lines.size() || begin.column < lines.back().size() || error->warning_) {
f0360d51 499 cy::position end(error->location_.end);
48e3be8a 500
f0360d51
JF
501 if (begin.line != lines.size()) {
502 std::cerr << " | ";
503 std::cerr << lines[begin.line - 1] << std::endl;
504 }
48e3be8a 505
c52a09b8 506 std::cerr << "....";
97c8a8fc 507 for (size_t i(0); i != begin.column; ++i)
f0360d51 508 std::cerr << '.';
48e3be8a 509 if (begin.line != end.line || begin.column == end.column)
f0360d51
JF
510 std::cerr << '^';
511 else for (size_t i(0), e(end.column - begin.column); i != e; ++i)
512 std::cerr << '^';
513 std::cerr << std::endl;
48e3be8a 514
f0360d51
JF
515 std::cerr << " | ";
516 std::cerr << error->message_ << std::endl;
48e3be8a 517
7e5391fd 518 add_history(command_.c_str());
b1589845 519 ++histlines;
1f8eae40
JF
520 goto restart;
521 }
522 }
057f943f 523
1f8eae40 524 driver.errors_.clear();
057f943f 525
7e5391fd 526 command_ += '\n';
1f8eae40
JF
527 prompt = "cy> ";
528 goto read;
057f943f
JF
529 }
530
b10bd496 531 if (driver.program_ == NULL)
1f8eae40 532 goto restart;
057f943f 533
7e5391fd
JF
534 if (client_ != -1)
535 code = command_;
967067aa
JF
536 else {
537 std::ostringstream str;
029bc65b 538 CYOutput out(str, options);
de9fc71b 539 Setup(out, driver, options);
3b52fd1a 540 out << *driver.program_;
967067aa
JF
541 code = str.str();
542 }
057f943f
JF
543 }
544
7e5391fd 545 add_history(command_.c_str());
b1589845 546 ++histlines;
057f943f 547
1f8eae40
JF
548 if (debug)
549 std::cout << code << std::endl;
057f943f 550
a3f4a8e1 551 Run(client_, code, fout_, expand);
b09da87b 552 }
057f943f 553
da858962
JF
554 if (append_history$ != NULL) {
555 _syscall(close(_syscall(open(histfile, O_CREAT | O_WRONLY, 0600))));
556 (*append_history$)(histlines, histfile);
557 } else {
558 write_history(histfile);
559 }
b1589845 560
a3f4a8e1
JF
561 fputs("\n", fout_);
562 fflush(fout_);
b09da87b 563}
057f943f 564
579ed526 565static void *Map(const char *path, size_t *psize) {
b09da87b
JF
566 int fd;
567 _syscall(fd = open(path, O_RDONLY));
057f943f 568
b09da87b
JF
569 struct stat stat;
570 _syscall(fstat(fd, &stat));
571 size_t size(stat.st_size);
057f943f 572
b09da87b 573 *psize = size;
057f943f 574
b09da87b
JF
575 void *base;
576 _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
057f943f 577
b09da87b
JF
578 _syscall(close(fd));
579 return base;
580}
057f943f 581
b6961e53 582void InjectLibrary(pid_t pid);
06edab7d 583
b6961e53 584int Main(int argc, char const * const argv[], char const * const envp[]) {
48e3be8a 585 bool tty(isatty(STDIN_FILENO));
75b0a457 586 bool compile(false);
de9fc71b 587 CYOptions options;
967067aa 588
e4676127 589 append_history$ = (int (*)(int, const char *)) (dlsym(RTLD_DEFAULT, "append_history"));
da858962 590
2aa77fd8
JF
591#ifdef CY_ATTACH
592 pid_t pid(_not(pid_t));
593#endif
594
06edab7d
JF
595 CYPool pool;
596 apr_getopt_t *state;
597 _aprcall(apr_getopt_init(&state, pool, argc, argv));
598
599 for (;;) {
600 char opt;
601 const char *arg;
602
603 apr_status_t status(apr_getopt(state,
604 "cg:n:"
2aa77fd8 605#ifdef CY_ATTACH
06edab7d 606 "p:"
2aa77fd8 607#endif
06edab7d
JF
608 "s"
609 , &opt, &arg));
610
611 switch (status) {
612 case APR_EOF:
613 goto getopt;
614 case APR_BADCH:
615 case APR_BADARG:
616 fprintf(stderr,
617 "usage: cycript [-c]"
2aa77fd8 618#ifdef CY_ATTACH
69caa5be 619 " [-p <pid|name>]"
2aa77fd8 620#endif
06edab7d
JF
621 " [<script> [<arg>...]]\n"
622 );
623 return 1;
624 default:
625 _aprcall(status);
626 }
967067aa 627
06edab7d
JF
628 switch (opt) {
629 case 'c':
630 compile = true;
631 break;
75b0a457 632
06edab7d
JF
633 case 'g':
634 if (false);
de9fc71b
JF
635 else if (strcmp(arg, "rename") == 0)
636 options.verbose_ = true;
cac61857 637#if YYDEBUG
5ef46cc0 638 else if (strcmp(arg, "bison") == 0)
06edab7d 639 bison_ = true;
cac61857 640#endif
06edab7d
JF
641 else {
642 fprintf(stderr, "invalid name for -g\n");
643 return 1;
644 }
645 break;
cac61857 646
06edab7d
JF
647 case 'n':
648 if (false);
5ef46cc0 649 else if (strcmp(arg, "minify") == 0)
06edab7d
JF
650 pretty_ = true;
651 else {
652 fprintf(stderr, "invalid name for -n\n");
653 return 1;
654 }
655 break;
11c1cc16 656
2aa77fd8 657#ifdef CY_ATTACH
06edab7d 658 case 'p': {
5ef46cc0 659 size_t size(strlen(arg));
06edab7d 660 char *end;
69caa5be 661
5ef46cc0
JF
662 pid = strtoul(arg, &end, 0);
663 if (arg + size != end) {
69caa5be
JF
664 // XXX: arg needs to be escaped in some horrendous way of doom
665 const char *command(apr_psprintf(pool, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^%s /{s/^[^ ]* //;q;};};d'", arg));
666
667 if (FILE *pids = popen(command, "r")) {
668 char value[32];
669 size = 0;
670
671 for (;;) {
672 size_t read(fread(value + size, 1, sizeof(value) - size, pids));
673 if (read == 0)
674 break;
675 else {
676 size += read;
677 if (size == sizeof(value)) {
678 pid = _not(pid_t);
b166b11b 679 goto fail;
69caa5be
JF
680 }
681 }
682 }
683
684 size:
685 if (size == 0)
b166b11b 686 goto fail;
69caa5be
JF
687 if (value[size - 1] == '\n') {
688 --size;
689 goto size;
690 }
691
692 value[size] = '\0';
693 size = strlen(value);
694 pid = strtoul(value, &end, 0);
b166b11b 695 if (value + size != end) fail:
69caa5be 696 pid = _not(pid_t);
69caa5be
JF
697 _syscall(pclose(pids));
698 }
699
700 if (pid == _not(pid_t)) {
701 fprintf(stderr, "invalid pid for -p\n");
702 return 1;
703 }
06edab7d
JF
704 }
705 } break;
2aa77fd8 706#endif
b10bd496 707
06edab7d
JF
708 case 's':
709 strict_ = true;
710 break;
711 }
967067aa
JF
712 } getopt:;
713
b09da87b 714 const char *script;
5ef46cc0 715 int ind(state->ind);
b09da87b 716
2aa77fd8 717#ifdef CY_ATTACH
5ef46cc0 718 if (pid != _not(pid_t) && ind < argc - 1) {
fcc64bb5
JF
719 fprintf(stderr, "-p cannot set argv\n");
720 return 1;
721 }
722
75b0a457
JF
723 if (pid != _not(pid_t) && compile) {
724 fprintf(stderr, "-p conflicts with -c\n");
725 return 1;
726 }
2aa77fd8 727#endif
75b0a457 728
5ef46cc0 729 if (ind == argc)
b09da87b
JF
730 script = NULL;
731 else {
9185d5ef 732#ifdef CY_EXECUTE
967067aa 733 // XXX: const_cast?! wtf gcc :(
5ef46cc0 734 CYSetArgs(argc - ind - 1, const_cast<const char **>(argv + ind + 1));
9185d5ef 735#endif
5ef46cc0 736 script = argv[ind];
967067aa
JF
737 if (strcmp(script, "-") == 0)
738 script = NULL;
b09da87b
JF
739 }
740
2aa77fd8
JF
741#ifdef CY_ATTACH
742 if (pid != _not(pid_t) && script == NULL && !tty) {
743 fprintf(stderr, "non-terminal attaching to remote console\n");
48e3be8a
JF
744 return 1;
745 }
2aa77fd8 746#endif
48e3be8a 747
2aa77fd8 748#ifdef CY_ATTACH
967067aa 749 if (pid == _not(pid_t))
7e5391fd 750 client_ = -1;
967067aa 751 else {
b166b11b
JF
752 int server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0))); try {
753 struct sockaddr_un address;
754 memset(&address, 0, sizeof(address));
755 address.sun_family = AF_UNIX;
756
757 sprintf(address.sun_path, "/tmp/.s.cy.%u", getpid());
758
759 _syscall(bind(server, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address)));
760 _syscall(chmod(address.sun_path, 0777));
761
762 try {
763 _syscall(listen(server, 1));
764 InjectLibrary(pid);
7e5391fd 765 client_ = _syscall(accept(server, NULL, NULL));
b166b11b
JF
766 } catch (...) {
767 // XXX: exception?
768 unlink(address.sun_path);
769 throw;
770 }
771 } catch (...) {
772 _syscall(close(server));
95678376 773 throw;
b166b11b 774 }
967067aa 775 }
2aa77fd8 776#else
7e5391fd 777 client_ = -1;
2aa77fd8 778#endif
579ed526 779
48e3be8a 780 if (script == NULL && tty)
2eb8215d 781 Console(options);
b09da87b 782 else {
2eb8215d
JF
783 CYLocalPool pool;
784 CYDriver driver(script ?: "<stdin>");
b09da87b 785 cy::parser parser(driver);
b10bd496 786 Setup(driver, parser);
b09da87b 787
48e3be8a 788 char *start, *end;
b09da87b 789
48e3be8a
JF
790 if (script == NULL) {
791 start = NULL;
792 end = NULL;
2b1245e4 793
48e3be8a
JF
794 driver.file_ = stdin;
795 } else {
796 size_t size;
797 start = reinterpret_cast<char *>(Map(script, &size));
798 end = start + size;
799
800 if (size >= 2 && start[0] == '#' && start[1] == '!') {
801 start += 2;
057f943f 802
48e3be8a
JF
803 if (void *line = memchr(start, '\n', end - start))
804 start = reinterpret_cast<char *>(line);
805 else
806 start = end;
807 }
808
809 driver.data_ = start;
810 driver.size_ = end - start;
811 }
62ca2b82 812
b09da87b
JF
813 if (parser.parse() != 0 || !driver.errors_.empty()) {
814 for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i)
815 std::cerr << i->location_.begin << ": " << i->message_ << std::endl;
b10bd496 816 } else if (driver.program_ != NULL)
7e5391fd 817 if (client_ != -1) {
e934f827 818 std::string code(start, end-start);
7e5391fd 819 Run(client_, code, stdout);
e934f827 820 } else {
fcc64bb5 821 std::ostringstream str;
029bc65b 822 CYOutput out(str, options);
de9fc71b 823 Setup(out, driver, options);
3b52fd1a 824 out << *driver.program_;
fcc64bb5 825 std::string code(str.str());
75b0a457
JF
826 if (compile)
827 std::cout << code;
98ea05a3 828 else
7e5391fd 829 Run(client_, code, stdout);
fcc64bb5 830 }
057f943f 831 }
62ca2b82 832
057f943f 833 return 0;
62ca2b82 834}
b6961e53
JF
835
836int main(int argc, char const * const argv[], char const * const envp[]) {
837 apr_status_t status(apr_app_initialize(&argc, &argv, &envp));
da858962 838
b6961e53
JF
839 if (status != APR_SUCCESS) {
840 fprintf(stderr, "apr_app_initialize() != APR_SUCCESS\n");
841 return 1;
842 } else try {
843 return Main(argc, argv, envp);
844 } catch (const CYException &error) {
845 CYPool pool;
846 fprintf(stderr, "%s\n", error.PoolCString(pool));
847 return 1;
848 }
849}