1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2015  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   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. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  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/>. 
  22 #include "cycript.hpp" 
  25 #include "JavaScript.hpp" 
  33 #ifdef HAVE_READLINE_H 
  36 #include <readline/readline.h> 
  42 #include <readline/history.h> 
  51 #include <sys/socket.h> 
  52 #include <sys/types.h> 
  57 #include <sys/ioctl.h> 
  58 #include <sys/types.h> 
  59 #include <sys/socket.h> 
  60 #include <netinet/in.h> 
  68 #include <mach/mach_time.h> 
  73 #include "Highlight.hpp" 
  76 extern "C" int rl_display_fixed
; 
  77 extern "C" int _rl_vis_botlin
; 
  78 extern "C" int _rl_last_c_pos
; 
  79 extern "C" int _rl_last_v_pos
; 
  81 typedef std::complex<int> CYCursor
; 
  83 static CYCursor current_
; 
  87 unsigned CYDisplayWidth() { 
  89     if (ioctl(1, TIOCGWINSZ
, &info
) != -1) 
  91     return tgetnum(const_cast<char *>("co")); 
  94 void CYDisplayOutput_(bool display
, const char *&data
) { 
  97         if (next 
== '\0' || next 
== CYIgnoreEnd
) 
 104 CYCursor 
CYDisplayOutput(bool display
, int width
, const char *data
, ssize_t offset 
= 0) { 
 105     CYCursor 
point(current_
); 
 110         switch (char next 
= *data
++) { 
 116                 CYDisplayOutput_(display
, data
); 
 124                 current_ 
+= CYCursor(0, 1); 
 125                 if (current_
.imag() != width
) 
 127                 current_ 
= CYCursor(current_
.real() + 1, 0); 
 133                 current_ 
= CYCursor(current_
.real() + 1, 4); 
 148 void CYDisplayMove_(char *negative
, char *positive
, int offset
) { 
 150         putp(tparm(negative
, -offset
)); 
 152         putp(tparm(positive
, offset
)); 
 155 void CYDisplayMove(CYCursor target
) { 
 156     CYCursor 
offset(target 
- current_
); 
 158     CYDisplayMove_(parm_up_cursor
, parm_down_cursor
, offset
.real()); 
 160     if (char *parm 
= tparm(column_address
, target
.imag())) 
 163         CYDisplayMove_(parm_left_cursor
, parm_right_cursor
, offset
.imag()); 
 168 void CYDisplayUpdate() { 
 169     current_ 
= CYCursor(_rl_last_v_pos
, _rl_last_c_pos
); 
 171     const char *prompt(rl_display_prompt
); 
 173     std::ostringstream stream
; 
 174     CYLexerHighlight(rl_line_buffer
, rl_end
, stream
, true); 
 175     std::string 
string(stream
.str()); 
 176     const char *buffer(string
.c_str()); 
 178     int width(CYDisplayWidth()); 
 179     if (width_ 
!= width
) { 
 180         current_ 
= CYCursor(); 
 181         CYDisplayOutput(false, width
, prompt
); 
 182         current_ 
= CYDisplayOutput(false, width
, buffer
, point_
); 
 185     CYDisplayMove(CYCursor()); 
 186     CYDisplayOutput(true, width
, prompt
); 
 187     CYCursor 
target(CYDisplayOutput(true, width
, stream
.str().c_str(), rl_point
)); 
 189     _rl_vis_botlin 
= current_
.real(); 
 191     if (current_
.imag() == 0) 
 192         CYDisplayOutput(true, width
, " "); 
 195     CYDisplayMove(target
); 
 198     _rl_last_v_pos 
= current_
.real(); 
 199     _rl_last_c_pos 
= current_
.imag(); 
 205 static volatile enum { 
 213 static jmp_buf ctrlc_
; 
 215 static void sigint(int) { 
 236 void Setup(CYDriver 
&driver
) { 
 240         driver
.strict_ 
= true; 
 243 void Setup(CYOutput 
&out
, CYDriver 
&driver
, CYOptions 
&options
, bool lower
) { 
 244     out
.pretty_ 
= pretty_
; 
 246         driver
.Replace(options
); 
 249 static CYUTF8String 
Run(CYPool 
&pool
, int client
, CYUTF8String code
) { 
 256         json 
= CYExecute(CYGetJSContext(), pool
, code
); 
 268         _assert(CYSendAll(client
, &size
, sizeof(size
))); 
 269         _assert(CYSendAll(client
, code
.data
, code
.size
)); 
 271         _assert(CYRecvAll(client
, &size
, sizeof(size
))); 
 272         if (size 
== _not(uint32_t)) 
 275             char *temp(new(pool
) char[size 
+ 1]); 
 276             _assert(CYRecvAll(client
, temp
, size
)); 
 283     return CYUTF8String(json
, size
); 
 286 static CYUTF8String 
Run(CYPool 
&pool
, int client
, const std::string 
&code
) { 
 287     return Run(pool
, client
, CYUTF8String(code
.c_str(), code
.size())); 
 290 static std::ostream 
*out_
; 
 292 static void Output(CYUTF8String json
, std::ostream 
*out
, bool expand 
= false) { 
 293     const char *data(json
.data
); 
 294     size_t size(json
.size
); 
 296     if (data 
== NULL 
|| out 
== NULL
) 
 300         data
[0] != '@' && data
[0] != '"' && data
[0] != '\'' || 
 301         data
[0] == '@' && data
[1] != '"' && data
[1] != '\'' 
 303         CYLexerHighlight(data
, size
, *out
); 
 304     else for (size_t i(0); i 
!= size
; ++i
) 
 307         else switch(data
[++i
]) { 
 308             case '\0': goto done
; 
 309             case '\\': *out 
<< '\\'; break; 
 310             case '\'': *out 
<< '\''; break; 
 311             case '"': *out 
<< '"'; break; 
 312             case 'b': *out 
<< '\b'; break; 
 313             case 'f': *out 
<< '\f'; break; 
 314             case 'n': *out 
<< '\n'; break; 
 315             case 'r': *out 
<< '\r'; break; 
 316             case 't': *out 
<< '\t'; break; 
 317             case 'v': *out 
<< '\v'; break; 
 318             default: *out 
<< '\\'; --i
; break; 
 325 int (*append_history$
)(int, const char *); 
 327 static std::string command_
; 
 331 static CYUTF8String 
Run(CYPool 
&pool
, const std::string 
&code
) { 
 332     return Run(pool
, client_
, code
); 
 335 static char **Complete(const char *word
, int start
, int end
) { 
 336     rl_attempted_completion_over 
= ~0; 
 337     std::string 
line(rl_line_buffer
, start
); 
 338     char **values(CYComplete(word
, command_ 
+ line
, &Run
)); 
 343 // need char *, not const char * 
 344 static char name_
[] = "cycript"; 
 345 static char break_
[] = " \t\n\"\\'`@><=;|&{(" ")}" ".:[]"; 
 349     std::string histfile_
; 
 353     History(std::string histfile
) : 
 357         read_history(histfile_
.c_str()); 
 359         for (HIST_ENTRY 
*history((history_set_pos(0), current_history())); history
; history 
= next_history()) 
 360             for (char *character(history
->line
); *character
; ++character
) 
 361                 if (*character 
== '\x01') *character 
= '\n'; 
 365         for (HIST_ENTRY 
*history((history_set_pos(0), current_history())); history
; history 
= next_history()) 
 366             for (char *character(history
->line
); *character
; ++character
) 
 367                 if (*character 
== '\n') *character 
= '\x01'; 
 369         if (append_history$ 
!= NULL
) { 
 370             int fd(_syscall(open(histfile_
.c_str(), O_CREAT 
| O_WRONLY
, 0600))); 
 372             _assert((*append_history$
)(histlines_
, histfile_
.c_str()) == 0); 
 374             _assert(write_history(histfile_
.c_str()) == 0); 
 378     void operator +=(std::string command
) { 
 379         add_history(command
.c_str()); 
 384 template <typename Type_
> 
 385 static Type_ 
*CYmemrchr(Type_ 
*data
, Type_ value
, size_t size
) { 
 387         if (data
[--size
] == value
) 
 392 static int CYConsoleKeyReturn(int count
, int key
) { 
 393     if (rl_point 
!= rl_end
) { 
 394         if (memchr(rl_line_buffer
, '\n', rl_end
) == NULL
) 
 395             return rl_newline(count
, key
); 
 398         char *before(CYmemrchr(rl_line_buffer
, '\n', rl_point
)); 
 400             before 
= rl_line_buffer
; 
 402         int space(before 
+ 1 - rl_line_buffer
); 
 403         while (space 
!= rl_point 
&& rl_line_buffer
[space
] == ' ') 
 406         int adjust(rl_line_buffer 
+ space 
- 1 - before
); 
 407         if (space 
== rl_point 
&& adjust 
!= 0) 
 408             rl_rubout(adjust
, '\b'); 
 410         rl_insert(count
, '\n'); 
 412             rl_insert(adjust
, ' '); 
 418     if (rl_line_buffer
[0] == '?') 
 421         std::string 
command(rl_line_buffer
, rl_end
); 
 423         std::stringbuf 
stream(command
); 
 425         size_t last(std::string::npos
); 
 426         for (size_t i(0); i 
!= std::string::npos
; i 
= command
.find('\n', i 
+ 1)) 
 430         CYDriver 
driver(pool
, stream
); 
 431         if (driver
.Parse() || !driver
.errors_
.empty()) 
 432             for (CYDriver::Errors::const_iterator 
error(driver
.errors_
.begin()); error 
!= driver
.errors_
.end(); ++error
) { 
 433                 if (error
->location_
.begin
.line 
!= last 
+ 1) 
 442         return rl_newline(count
, key
); 
 444     // XXX: this was the most obvious fix, but is seriously dumb 
 448 static int CYConsoleKeyUp(int count
, int key
) { 
 449     while (count
-- != 0) { 
 450         char *after(CYmemrchr(rl_line_buffer
, '\n', rl_point
)); 
 452             if (int value 
= rl_get_previous_history(1, key
)) 
 457         char *before(CYmemrchr(rl_line_buffer
, '\n', after 
- rl_line_buffer
)); 
 459             before 
= rl_line_buffer 
- 1; 
 461         ptrdiff_t offset(rl_line_buffer 
+ rl_point 
- after
); 
 462         if (offset 
> after 
- before
) 
 463             rl_point 
= after 
- rl_line_buffer
; 
 465             rl_point 
= before 
+ offset 
- rl_line_buffer
; 
 471 static int CYConsoleKeyDown(int count
, int key
) { 
 472     while (count
-- != 0) { 
 473         char *after(static_cast<char *>(memchr(rl_line_buffer 
+ rl_point
, '\n', rl_end 
- rl_point
))); 
 475             int where(where_history()); 
 476             if (int value 
= rl_get_next_history(1, key
)) 
 478             if (where 
!= where_history()) { 
 479                 char *first(static_cast<char *>(memchr(rl_line_buffer
, '\n', rl_end
))); 
 481                     rl_point 
= first 
- 1 - rl_line_buffer
; 
 486         char *before(CYmemrchr(rl_line_buffer
, '\n', rl_point
)); 
 488             before 
= rl_line_buffer 
- 1; 
 490         char *next(static_cast<char *>(memchr(after 
+ 1, '\n', rl_line_buffer 
+ rl_end 
- after 
- 1))); 
 492             next 
= rl_line_buffer 
+ rl_end
; 
 494         ptrdiff_t offset(rl_line_buffer 
+ rl_point 
- before
); 
 495         if (offset 
> next 
- after
) 
 496             rl_point 
= next 
- rl_line_buffer
; 
 498             rl_point 
= after 
+ offset 
- rl_line_buffer
; 
 504 static int CYConsoleLineBegin(int count
, int key
) { 
 505     while (rl_point 
!= 0 && rl_line_buffer
[rl_point 
- 1] != '\n') 
 510 static int CYConsoleLineEnd(int count
, int key
) { 
 511     while (rl_point 
!= rl_end 
&& rl_line_buffer
[rl_point
] != '\n') 
 513     if (rl_point 
!= rl_end 
&& rl_editing_mode 
== 0) 
 518 static int CYConsoleKeyBack(int count
, int key
) { 
 519     while (count
-- != 0) { 
 520         char *before(CYmemrchr(rl_line_buffer
, '\n', rl_point
)); 
 522             return rl_rubout(count
, key
); 
 524         int start(before 
+ 1 - rl_line_buffer
); 
 525         if (start 
== rl_point
) rubout
: { 
 530         for (int i(start
); i 
!= rl_point
; ++i
) 
 531             if (rl_line_buffer
[i
] != ' ') 
 533         rl_rubout((rl_point 
- start
) % 4 ?: 4, key
); 
 539 static int CYConsoleKeyTab(int count
, int key
) { 
 540     char *before(CYmemrchr(rl_line_buffer
, '\n', rl_point
)); 
 541     if (before 
== NULL
) complete
: 
 542         return rl_complete_internal(rl_completion_mode(&CYConsoleKeyTab
)); 
 543     int start(before 
+ 1 - rl_line_buffer
); 
 544     for (int i(start
); i 
!= rl_point
; ++i
) 
 545         if (rl_line_buffer
[i
] != ' ') 
 547     return rl_insert(4 - (rl_point 
- start
) % 4, ' '); 
 550 static void CYConsoleRemapBind(Keymap map
, rl_command_func_t 
*from
, rl_command_func_t 
*to
) { 
 551     char **keyseqs(rl_invoking_keyseqs_in_map(from
, map
)); 
 554     for (char **keyseq(keyseqs
); *keyseq 
!= NULL
; ++keyseq
) { 
 555         rl_bind_keyseq_in_map(*keyseq
, to
, map
); 
 561 static void CYConsoleRemapKeys(Keymap map
) { 
 562     CYConsoleRemapBind(map
, &rl_beg_of_line
, &CYConsoleLineBegin
); 
 563     CYConsoleRemapBind(map
, &rl_end_of_line
, &CYConsoleLineEnd
); 
 565     CYConsoleRemapBind(map
, &rl_get_previous_history
, &CYConsoleKeyUp
); 
 566     CYConsoleRemapBind(map
, &rl_get_next_history
, &CYConsoleKeyDown
); 
 568     CYConsoleRemapBind(map
, &rl_rubout
, &CYConsoleKeyBack
); 
 569     CYConsoleRemapBind(map
, &rl_complete
, &CYConsoleKeyTab
); 
 572 static void CYConsolePrepTerm(int meta
) { 
 573     rl_prep_terminal(meta
); 
 575     CYConsoleRemapKeys(emacs_standard_keymap
); 
 576     CYConsoleRemapKeys(emacs_meta_keymap
); 
 577     CYConsoleRemapKeys(emacs_ctlx_keymap
); 
 578     CYConsoleRemapKeys(vi_insertion_keymap
); 
 579     CYConsoleRemapKeys(vi_movement_keymap
); 
 582 static void Console(CYOptions 
&options
) { 
 584     if (const char *home 
= getenv("HOME")) 
 588         if (const char *username 
= getenv("LOGNAME")) 
 589             passwd 
= getpwnam(username
); 
 591             passwd 
= getpwuid(getuid()); 
 592         basedir 
= passwd
->pw_dir
; 
 595     basedir 
+= "/.cycript"; 
 596     mkdir(basedir
.c_str(), 0700); 
 599     rl_readline_name 
= name_
; 
 601     History 
history(basedir 
+ "/history"); 
 610     rl_completer_word_break_characters 
= break_
; 
 611     rl_attempted_completion_function 
= &Complete
; 
 613     rl_redisplay_function 
= CYDisplayUpdate
; 
 614     rl_prep_term_function 
= CYConsolePrepTerm
; 
 616     struct sigaction action
; 
 617     sigemptyset(&action
.sa_mask
); 
 618     action
.sa_handler 
= &sigint
; 
 620     sigaction(SIGINT
, &action
, NULL
); 
 623         if (setjmp(ctrlc_
) != 0) { 
 630             rl_bind_key('\r', &rl_newline
); 
 631             rl_bind_key('\n', &rl_newline
); 
 633             rl_bind_key('\r', &CYConsoleKeyReturn
); 
 634             rl_bind_key('\n', &CYConsoleKeyReturn
); 
 638         char *line(readline("cy# ")); 
 646         std::string 
command(line
); 
 652         if (command
[0] == '?') { 
 653             std::string 
data(command
.substr(1)); 
 654             if (data 
== "bypass") { 
 656                 *out_ 
<< "bypass == " << (bypass 
? "true" : "false") << std::endl
; 
 657             } else if (data 
== "debug") { 
 659                 *out_ 
<< "debug == " << (debug 
? "true" : "false") << std::endl
; 
 660             } else if (data 
== "destroy") { 
 662             } else if (data 
== "gc") { 
 663                 *out_ 
<< "collecting... " << std::flush
; 
 664                 CYGarbageCollect(CYGetJSContext()); 
 665                 *out_ 
<< "done." << std::endl
; 
 666             } else if (data 
== "exit") { 
 668             } else if (data 
== "expand") { 
 670                 *out_ 
<< "expand == " << (expand 
? "true" : "false") << std::endl
; 
 671             } else if (data 
== "lower") { 
 673                 *out_ 
<< "lower == " << (lower 
? "true" : "false") << std::endl
; 
 683             std::stringbuf 
stream(command
); 
 686             CYDriver 
driver(pool
, stream
); 
 689             if (driver
.Parse() || !driver
.errors_
.empty()) { 
 690                 for (CYDriver::Errors::const_iterator 
error(driver
.errors_
.begin()); error 
!= driver
.errors_
.end(); ++error
) { 
 691                     CYPosition 
begin(error
->location_
.begin
); 
 692                     CYPosition 
end(error
->location_
.end
); 
 694                     /*if (begin.line != lines2.size()) { 
 696                         std::cerr << lines2[begin.line - 1] << std::endl; 
 700                     for (size_t i(0); i 
!= begin
.column
; ++i
) 
 702                     if (begin
.line 
!= end
.line 
|| begin
.column 
== end
.column
) 
 704                     else for (size_t i(0), e(end
.column 
- begin
.column
); i 
!= e
; ++i
) 
 706                     std::cerr 
<< std::endl
; 
 709                     std::cerr 
<< error
->message_ 
<< std::endl
; 
 717             if (driver
.script_ 
== NULL
) 
 721             CYOutput 
out(str
, options
); 
 722             Setup(out
, driver
, options
, lower
); 
 723             out 
<< *driver
.script_
; 
 725         } catch (const CYException 
&error
) { 
 727             std::cout 
<< error
.PoolCString(pool
) << std::endl
; 
 733             CYLexerHighlight(code
.c_str(), code
.size(), std::cout
); 
 734             std::cout 
<< std::endl
; 
 738         Output(Run(pool
, client_
, code
), &std::cout
, expand
); 
 742 void InjectLibrary(pid_t
, int, const char *const []); 
 744 static uint64_t CYGetTime() { 
 746     return mach_absolute_time(); 
 748     struct timespec spec
; 
 749     clock_gettime(CLOCK_MONOTONIC
, &spec
); 
 750     return spec
.tv_sec 
* UINT64_C(1000000000) + spec
.tv_nsec
; 
 754 int Main(int argc
, char * const argv
[], char const * const envp
[]) { 
 755     bool tty(isatty(STDIN_FILENO
)); 
 760     append_history$ 
= (int (*)(int, const char *)) (dlsym(RTLD_DEFAULT
, "append_history")); 
 763     pid_t 
pid(_not(pid_t
)); 
 766     const char *host(NULL
); 
 767     const char *port(NULL
); 
 772         int option(getopt_long(argc
, argv
, 
 781         , (const struct option
[]) { 
 782             {NULL
, no_argument
, NULL
, 'c'}, 
 783             {NULL
, required_argument
, NULL
, 'g'}, 
 784             {NULL
, required_argument
, NULL
, 'n'}, 
 786             {NULL
, required_argument
, NULL
, 'p'}, 
 788             {NULL
, required_argument
, NULL
, 'r'}, 
 789             {NULL
, no_argument
, NULL
, 's'}, 
 790         {0, 0, 0, 0}}, NULL
)); 
 799                     "usage: cycript [-c]" 
 804                     " [<script> [<arg>...]]\n" 
 812                     fprintf(stderr
, "only one of -[c" 
 816                     "r] may be used at a time\n"); 
 827                 else if (strcmp(optarg
, "rename") == 0) 
 828                     options
.verbose_ 
= true; 
 829                 else if (strcmp(optarg
, "bison") == 0) 
 831                 else if (strcmp(optarg
, "timing") == 0) 
 834                     fprintf(stderr
, "invalid name for -g\n"); 
 841                 else if (strcmp(optarg
, "minify") == 0) 
 844                     fprintf(stderr
, "invalid name for -n\n"); 
 851                 size_t size(strlen(optarg
)); 
 854                 pid 
= strtoul(optarg
, &end
, 0); 
 855                 if (optarg 
+ size 
!= end
) { 
 856                     // XXX: arg needs to be escaped in some horrendous way of doom 
 857                     // XXX: this is a memory leak now because I just don't care enough 
 859                     int writ(asprintf(&command
, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^%s /{s/^[^ ]* //;q;};};d'", optarg
)); 
 862                     if (FILE *pids 
= popen(command
, "r")) { 
 867                             size_t read(fread(value 
+ size
, 1, sizeof(value
) - size
, pids
)); 
 872                                 if (size 
== sizeof(value
)) 
 880                         if (value
[size 
- 1] == '\n') { 
 886                         size 
= strlen(value
); 
 887                         pid 
= strtoul(value
, &end
, 0); 
 888                         if (value 
+ size 
!= end
) fail
: 
 890                         _syscall(pclose(pids
)); 
 893                     if (pid 
== _not(pid_t
)) { 
 894                         fprintf(stderr
, "unable to find process `%s' using ps\n", optarg
); 
 902                 //size_t size(strlen(optarg)); 
 904                 char *colon(strrchr(optarg
, ':')); 
 906                     fprintf(stderr
, "missing colon in hostspec\n"); 
 911                 port = strtoul(colon + 1, &end, 10); 
 912                 if (end != optarg + size) { 
 913                     fprintf(stderr, "invalid port in hostspec\n"); 
 938     if (pid 
!= _not(pid_t
) && argc 
> 1) { 
 939         fprintf(stderr
, "-p cannot set argv\n"); 
 948         // XXX: const_cast?! wtf gcc :( 
 949         CYSetArgs(argc 
- 1, const_cast<const char **>(argv 
+ 1)); 
 952         if (strcmp(script
, "-") == 0) 
 957     if (pid 
== _not(pid_t
)) 
 975         } server(_syscall(socket(PF_UNIX
, SOCK_STREAM
, 0))); 
 977         struct sockaddr_un address
; 
 978         memset(&address
, 0, sizeof(address
)); 
 979         address
.sun_family 
= AF_UNIX
; 
 982 #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) 
 983         tmp 
= "/Library/Caches"; 
 988         sprintf(address
.sun_path
, "%s/.s.cy.%u", tmp
, getpid()); 
 989         unlink(address
.sun_path
); 
 994             File(const char *path
) : 
1002         } file(address
.sun_path
); 
1004         _syscall(bind(server
, reinterpret_cast<sockaddr 
*>(&address
), SUN_LEN(&address
))); 
1005         _syscall(chmod(address
.sun_path
, 0777)); 
1007         _syscall(listen(server
, 1)); 
1008         const char *const argv
[] = {address
.sun_path
, NULL
}; 
1009         InjectLibrary(pid
, 1, argv
); 
1010         client_ 
= _syscall(accept(server
, NULL
, NULL
)); 
1016     if (client_ 
== -1 && host 
!= NULL 
&& port 
!= NULL
) { 
1017         struct addrinfo hints
; 
1018         memset(&hints
, 0, sizeof(hints
)); 
1019         hints
.ai_family 
= AF_UNSPEC
; 
1020         hints
.ai_socktype 
= SOCK_STREAM
; 
1021         hints
.ai_protocol 
= 0; 
1024         struct addrinfo 
*infos
; 
1025         _syscall(getaddrinfo(host
, port
, &hints
, &infos
)); 
1027         _assert(infos 
!= NULL
); try { 
1028             for (struct addrinfo 
*info(infos
); info 
!= NULL
; info 
= info
->ai_next
) { 
1029                 int client(_syscall(socket(info
->ai_family
, info
->ai_socktype
, info
->ai_protocol
))); try { 
1030                     _syscall(connect(client
, info
->ai_addr
, info
->ai_addrlen
)); 
1034                     _syscall(close(client
)); 
1039             freeaddrinfo(infos
); 
1044     if (script 
== NULL 
&& tty
) 
1047         std::istream 
*stream
; 
1048         if (script 
== NULL
) { 
1052             stream 
= new std::fstream(script
, std::ios::in 
| std::ios::binary
); 
1053             _assert(!stream
->fail()); 
1057             std::stringbuf buffer
; 
1058             stream
->get(buffer
, '\0'); 
1059             _assert(!stream
->fail()); 
1063             uint64_t start(CYGetTime()); 
1066                 stream 
= new std::istringstream(buffer
.str()); 
1069                 CYDriver 
driver(pool
, *stream
->rdbuf(), script
); 
1072                 uint64_t begin(CYGetTime()); 
1074                 uint64_t end(CYGetTime()); 
1078                 average 
+= (end 
- begin 
- average
) / ++samples
; 
1080                 uint64_t now(CYGetTime()); 
1083                 else if ((now 
- start
) / 1000000000 >= 1) 
1084                     std::cout 
<< std::fixed 
<< average 
<< '\t' << (end 
- begin
) << '\t' << samples 
<< std::endl
; 
1090             stream 
= new std::istringstream(buffer
.str()); 
1095         CYDriver 
driver(pool
, *stream
->rdbuf(), script
); 
1098         bool failed(driver
.Parse()); 
1100         if (failed 
|| !driver
.errors_
.empty()) { 
1101             for (CYDriver::Errors::const_iterator 
i(driver
.errors_
.begin()); i 
!= driver
.errors_
.end(); ++i
) 
1102                 std::cerr 
<< i
->location_
.begin 
<< ": " << i
->message_ 
<< std::endl
; 
1104         } else if (driver
.script_ 
!= NULL
) { 
1106             CYOutput 
out(str
, options
); 
1107             Setup(out
, driver
, options
, true); 
1108             out 
<< *driver
.script_
; 
1109             std::string 
code(str
.str()); 
1113                 CYUTF8String 
json(Run(pool
, client_
, code
)); 
1114                 if (CYStartsWith(json
, "throw ")) { 
1115                     CYLexerHighlight(json
.data
, json
.size
, std::cerr
); 
1116                     std::cerr 
<< std::endl
; 
1126 int main(int argc
, char * const argv
[], char const * const envp
[]) { 
1128         return Main(argc
, argv
, envp
); 
1129     } catch (const CYException 
&error
) { 
1131         fprintf(stderr
, "%s\n", error
.PoolCString(pool
));