1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <assert.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20 21#include "jerryscript.h" 22#include "jerryscript-ext/debugger.h" 23#include "jerryscript-ext/handler.h" 24#include "jerryscript-port.h" 25#include "jerryscript-port-default.h" 26 27#include "cli.h" 28 29/** 30 * Maximum size of source code 31 */ 32#define JERRY_BUFFER_SIZE (1048576) 33 34/** 35 * Maximum size of snapshots buffer 36 */ 37#define JERRY_SNAPSHOT_BUFFER_SIZE (JERRY_BUFFER_SIZE / sizeof (uint32_t)) 38 39/** 40 * Standalone Jerry exit codes 41 */ 42#define JERRY_STANDALONE_EXIT_CODE_OK (0) 43#define JERRY_STANDALONE_EXIT_CODE_FAIL (1) 44 45/** 46 * Context size of the SYNTAX_ERROR 47 */ 48#define SYNTAX_ERROR_CONTEXT_SIZE 2 49 50static uint8_t buffer[ JERRY_BUFFER_SIZE ]; 51 52static const uint32_t * 53read_file (const char *file_name, 54 size_t *out_size_p) 55{ 56 if (file_name == NULL) 57 { 58 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file, missing filename\n"); 59 return NULL; 60 } 61 62 FILE *file; 63 if (!strcmp ("-", file_name)) 64 { 65 file = stdin; 66 } 67 else 68 { 69 file = fopen (file_name, "rb"); 70 if (file == NULL) 71 { 72 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name); 73 return NULL; 74 } 75 } 76 77 size_t bytes_read = fread (buffer, 1u, sizeof (buffer), file); 78 if (!bytes_read) 79 { 80 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name); 81 fclose (file); 82 return NULL; 83 } 84 85 fclose (file); 86 87 *out_size_p = bytes_read; 88 return (const uint32_t *) buffer; 89} /* read_file */ 90 91/** 92 * Print error value 93 */ 94static void 95print_unhandled_exception (jerry_value_t error_value) /**< error value */ 96{ 97 assert (!jerry_value_is_error (error_value)); 98 99 jerry_char_t err_str_buf[256]; 100 101 if (jerry_value_is_object (error_value)) 102 { 103 jerry_value_t stack_str = jerry_create_string ((const jerry_char_t *) "stack"); 104 jerry_value_t backtrace_val = jerry_get_property (error_value, stack_str); 105 jerry_release_value (stack_str); 106 107 if (!jerry_value_is_error (backtrace_val) 108 && jerry_value_is_array (backtrace_val)) 109 { 110 printf ("Exception backtrace:\n"); 111 112 uint32_t length = jerry_get_array_length (backtrace_val); 113 114 /* This length should be enough. */ 115 if (length > 32) 116 { 117 length = 32; 118 } 119 120 for (uint32_t i = 0; i < length; i++) 121 { 122 jerry_value_t item_val = jerry_get_property_by_index (backtrace_val, i); 123 124 if (!jerry_value_is_error (item_val) 125 && jerry_value_is_string (item_val)) 126 { 127 jerry_size_t str_size = jerry_get_utf8_string_size (item_val); 128 129 if (str_size >= 256) 130 { 131 printf ("%3u: [Backtrace string too long]\n", i); 132 } 133 else 134 { 135 jerry_size_t string_end = jerry_string_to_utf8_char_buffer (item_val, err_str_buf, str_size); 136 assert (string_end == str_size); 137 err_str_buf[string_end] = 0; 138 139 printf ("%3u: %s\n", i, err_str_buf); 140 } 141 } 142 143 jerry_release_value (item_val); 144 } 145 } 146 jerry_release_value (backtrace_val); 147 } 148 149 jerry_value_t err_str_val = jerry_value_to_string (error_value); 150 jerry_size_t err_str_size = jerry_get_utf8_string_size (err_str_val); 151 152 if (err_str_size >= 256) 153 { 154 const char msg[] = "[Error message too long]"; 155 err_str_size = sizeof (msg) / sizeof (char) - 1; 156 memcpy (err_str_buf, msg, err_str_size + 1); 157 } 158 else 159 { 160 jerry_size_t string_end = jerry_string_to_utf8_char_buffer (err_str_val, err_str_buf, err_str_size); 161 assert (string_end == err_str_size); 162 err_str_buf[string_end] = 0; 163 164 if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) 165 && jerry_get_error_type (error_value) == JERRY_ERROR_SYNTAX) 166 { 167 jerry_char_t *string_end_p = err_str_buf + string_end; 168 unsigned int err_line = 0; 169 unsigned int err_col = 0; 170 char *path_str_p = NULL; 171 char *path_str_end_p = NULL; 172 173 /* 1. parse column and line information */ 174 for (jerry_char_t *current_p = err_str_buf; current_p < string_end_p; current_p++) 175 { 176 if (*current_p == '[') 177 { 178 current_p++; 179 180 if (*current_p == '<') 181 { 182 break; 183 } 184 185 path_str_p = (char *) current_p; 186 while (current_p < string_end_p && *current_p != ':') 187 { 188 current_p++; 189 } 190 191 path_str_end_p = (char *) current_p++; 192 193 err_line = (unsigned int) strtol ((char *) current_p, (char **) ¤t_p, 10); 194 195 current_p++; 196 197 err_col = (unsigned int) strtol ((char *) current_p, NULL, 10); 198 break; 199 } 200 } /* for */ 201 202 if (err_line != 0 && err_col != 0) 203 { 204 unsigned int curr_line = 1; 205 206 bool is_printing_context = false; 207 unsigned int pos = 0; 208 209 size_t source_size; 210 211 /* Temporarily modify the error message, so we can use the path. */ 212 *path_str_end_p = '\0'; 213 214 read_file (path_str_p, &source_size); 215 216 /* Revert the error message. */ 217 *path_str_end_p = ':'; 218 219 /* 2. seek and print */ 220 while ((pos < source_size) && (buffer[pos] != '\0')) 221 { 222 if (buffer[pos] == '\n') 223 { 224 curr_line++; 225 } 226 227 if (err_line < SYNTAX_ERROR_CONTEXT_SIZE 228 || (err_line >= curr_line 229 && (err_line - curr_line) <= SYNTAX_ERROR_CONTEXT_SIZE)) 230 { 231 /* context must be printed */ 232 is_printing_context = true; 233 } 234 235 if (curr_line > err_line) 236 { 237 break; 238 } 239 240 if (is_printing_context) 241 { 242 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%c", buffer[pos]); 243 } 244 245 pos++; 246 } 247 248 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "\n"); 249 250 while (--err_col) 251 { 252 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "~"); 253 } 254 255 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "^\n"); 256 } 257 } 258 } 259 260 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Script Error: %s\n", err_str_buf); 261 jerry_release_value (err_str_val); 262} /* print_unhandled_exception */ 263 264/** 265 * Register a JavaScript function in the global object. 266 */ 267static void 268register_js_function (const char *name_p, /**< name of the function */ 269 jerry_external_handler_t handler_p) /**< function callback */ 270{ 271 jerry_value_t result_val = jerryx_handler_register_global ((const jerry_char_t *) name_p, handler_p); 272 273 if (jerry_value_is_error (result_val)) 274 { 275 jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p); 276 result_val = jerry_get_value_from_error (result_val, true); 277 print_unhandled_exception (result_val); 278 } 279 280 jerry_release_value (result_val); 281} /* register_js_function */ 282 283/** 284 * Runs the source code received by jerry_debugger_wait_for_client_source. 285 * 286 * @return result fo the source code execution 287 */ 288static jerry_value_t 289wait_for_source_callback (const jerry_char_t *resource_name_p, /**< resource name */ 290 size_t resource_name_size, /**< size of resource name */ 291 const jerry_char_t *source_p, /**< source code */ 292 size_t source_size, /**< source code size */ 293 void *user_p) /**< user pointer */ 294{ 295 (void) user_p; /* unused */ 296 jerry_value_t ret_val = jerry_parse (resource_name_p, 297 resource_name_size, 298 source_p, 299 source_size, 300 JERRY_PARSE_NO_OPTS); 301 302 if (!jerry_value_is_error (ret_val)) 303 { 304 jerry_value_t func_val = ret_val; 305 ret_val = jerry_run (func_val); 306 jerry_release_value (func_val); 307 } 308 309 return ret_val; 310} /* wait_for_source_callback */ 311 312/** 313 * Command line option IDs 314 */ 315typedef enum 316{ 317 OPT_HELP, 318 OPT_VERSION, 319 OPT_MEM_STATS, 320 OPT_PARSE_ONLY, 321 OPT_SHOW_OP, 322 OPT_SHOW_RE_OP, 323 OPT_DEBUG_SERVER, 324 OPT_DEBUG_PORT, 325 OPT_DEBUG_CHANNEL, 326 OPT_DEBUG_PROTOCOL, 327 OPT_DEBUG_SERIAL_CONFIG, 328 OPT_DEBUGGER_WAIT_SOURCE, 329 OPT_EXEC_SNAP, 330 OPT_EXEC_SNAP_FUNC, 331 OPT_LOG_LEVEL, 332 OPT_NO_PROMPT, 333 OPT_CALL_ON_EXIT 334} main_opt_id_t; 335 336/** 337 * Command line options 338 */ 339static const cli_opt_t main_opts[] = 340{ 341 CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help", 342 .help = "print this help and exit"), 343 CLI_OPT_DEF (.id = OPT_VERSION, .opt = "v", .longopt = "version", 344 .help = "print tool and library version and exit"), 345 CLI_OPT_DEF (.id = OPT_MEM_STATS, .longopt = "mem-stats", 346 .help = "dump memory statistics"), 347 CLI_OPT_DEF (.id = OPT_PARSE_ONLY, .longopt = "parse-only", 348 .help = "don't execute JS input"), 349 CLI_OPT_DEF (.id = OPT_SHOW_OP, .longopt = "show-opcodes", 350 .help = "dump parser byte-code"), 351 CLI_OPT_DEF (.id = OPT_SHOW_RE_OP, .longopt = "show-regexp-opcodes", 352 .help = "dump regexp byte-code"), 353 CLI_OPT_DEF (.id = OPT_DEBUG_SERVER, .longopt = "start-debug-server", 354 .help = "start debug server and wait for a connecting client"), 355 CLI_OPT_DEF (.id = OPT_DEBUG_PORT, .longopt = "debug-port", .meta = "NUM", 356 .help = "debug server port (default: 5001)"), 357 CLI_OPT_DEF (.id = OPT_DEBUG_CHANNEL, .longopt = "debug-channel", .meta = "[websocket|rawpacket]", 358 .help = "Specify the debugger transmission channel (default: websocket)"), 359 CLI_OPT_DEF (.id = OPT_DEBUG_PROTOCOL, .longopt = "debug-protocol", .meta = "PROTOCOL", 360 .help = "Specify the transmission protocol over the communication channel (tcp|serial, default: tcp)"), 361 CLI_OPT_DEF (.id = OPT_DEBUG_SERIAL_CONFIG, .longopt = "serial-config", .meta = "OPTIONS_STRING", 362 .help = "Configure parameters for serial port (default: /dev/ttyS0,115200,8,N,1)"), 363 CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source", 364 .help = "wait for an executable source from the client"), 365 CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE", 366 .help = "execute input snapshot file(s)"), 367 CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM", 368 .help = "execute specific function from input snapshot file(s)"), 369 CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM", 370 .help = "set log level (0-3)"), 371 CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt", 372 .help = "don't print prompt in REPL mode"), 373 CLI_OPT_DEF (.id = OPT_CALL_ON_EXIT, .longopt = "call-on-exit", .meta = "STRING", 374 .help = "invoke the specified function when the process is just about to exit"), 375 CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE", 376 .help = "input JS file(s) (If file is -, read standard input.)") 377}; 378 379/** 380 * Check whether JerryScript has a requested feature enabled or not. If not, 381 * print a warning message. 382 * 383 * @return the status of the feature. 384 */ 385static bool 386check_feature (jerry_feature_t feature, /**< feature to check */ 387 const char *option) /**< command line option that triggered this check */ 388{ 389 if (!jerry_is_feature_enabled (feature)) 390 { 391 jerry_port_default_set_log_level (JERRY_LOG_LEVEL_WARNING); 392 jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Ignoring '%s' option because this feature is disabled!\n", option); 393 return false; 394 } 395 return true; 396} /* check_feature */ 397 398/** 399 * Check whether a usage-related condition holds. If not, print an error 400 * message, print the usage, and terminate the application. 401 */ 402static void 403check_usage (bool condition, /**< the condition that must hold */ 404 const char *name, /**< name of the application (argv[0]) */ 405 const char *msg, /**< error message to print if condition does not hold */ 406 const char *opt) /**< optional part of the error message */ 407{ 408 if (!condition) 409 { 410 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%s: %s%s\n", name, msg, opt != NULL ? opt : ""); 411 exit (JERRY_STANDALONE_EXIT_CODE_FAIL); 412 } 413} /* check_usage */ 414 415#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) 416 417/** 418 * The alloc function passed to jerry_create_context 419 */ 420static void * 421context_alloc (size_t size, 422 void *cb_data_p) 423{ 424 (void) cb_data_p; /* unused */ 425 return malloc (size); 426} /* context_alloc */ 427 428#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ 429 430/** 431 * Inits the engine and the debugger 432 */ 433static void 434init_engine (jerry_init_flag_t flags, /**< initialized flags for the engine */ 435 char *debug_channel, /**< enable the debugger init or not */ 436 char *debug_protocol, /**< enable the debugger init or not */ 437 uint16_t debug_port, /**< the debugger port for tcp protocol */ 438 char *debug_serial_config) /**< configuration string for serial protocol */ 439{ 440 jerry_init (flags); 441 if (strcmp (debug_channel, "")) 442 { 443 bool protocol = false; 444 445 if (!strcmp (debug_protocol, "tcp")) 446 { 447 protocol = jerryx_debugger_tcp_create (debug_port); 448 } 449 else 450 { 451 assert (!strcmp (debug_protocol, "serial")); 452 protocol = jerryx_debugger_serial_create (debug_serial_config); 453 } 454 455 if (!strcmp (debug_channel, "rawpacket")) 456 { 457 jerryx_debugger_after_connect (protocol && jerryx_debugger_rp_create ()); 458 } 459 else 460 { 461 assert (!strcmp (debug_channel, "websocket")); 462 jerryx_debugger_after_connect (protocol && jerryx_debugger_ws_create ()); 463 } 464 } 465 466 register_js_function ("assert", jerryx_handler_assert); 467 register_js_function ("gc", jerryx_handler_gc); 468 register_js_function ("print", jerryx_handler_print); 469 register_js_function ("resourceName", jerryx_handler_resource_name); 470} /* init_engine */ 471 472int 473main (int argc, 474 char **argv) 475{ 476 union 477 { 478 double d; 479 unsigned u; 480 } now = { .d = jerry_port_get_current_time () }; 481 srand (now.u); 482 JERRY_VLA (const char *, file_names, argc); 483 int files_counter = 0; 484 485 jerry_init_flag_t flags = JERRY_INIT_EMPTY; 486 487 JERRY_VLA (const char *, exec_snapshot_file_names, argc); 488 JERRY_VLA (uint32_t, exec_snapshot_file_indices, argc); 489 int exec_snapshots_count = 0; 490 491 bool is_parse_only = false; 492 493 bool start_debug_server = false; 494 uint16_t debug_port = 5001; 495 char *debug_channel = "websocket"; 496 char *debug_protocol = "tcp"; 497 char *debug_serial_config = "/dev/ttyS0,115200,8,N,1"; 498 499 bool is_repl_mode = false; 500 bool is_wait_mode = false; 501 bool no_prompt = false; 502 503 const char *exit_cb = NULL; 504 505 cli_state_t cli_state = cli_init (main_opts, argc - 1, argv + 1); 506 for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state)) 507 { 508 switch (id) 509 { 510 case OPT_HELP: 511 { 512 cli_help (argv[0], NULL, main_opts); 513 return JERRY_STANDALONE_EXIT_CODE_OK; 514 } 515 case OPT_VERSION: 516 { 517 printf ("Version: %d.%d.%d%s\n", 518 JERRY_API_MAJOR_VERSION, 519 JERRY_API_MINOR_VERSION, 520 JERRY_API_PATCH_VERSION, 521 JERRY_COMMIT_HASH); 522 return JERRY_STANDALONE_EXIT_CODE_OK; 523 } 524 case OPT_MEM_STATS: 525 { 526 if (check_feature (JERRY_FEATURE_MEM_STATS, cli_state.arg)) 527 { 528 jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); 529 flags |= JERRY_INIT_MEM_STATS; 530 } 531 break; 532 } 533 case OPT_PARSE_ONLY: 534 { 535 is_parse_only = true; 536 break; 537 } 538 case OPT_SHOW_OP: 539 { 540 if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state.arg)) 541 { 542 jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); 543 flags |= JERRY_INIT_SHOW_OPCODES; 544 } 545 break; 546 } 547 case OPT_CALL_ON_EXIT: 548 { 549 exit_cb = cli_consume_string (&cli_state); 550 break; 551 } 552 case OPT_SHOW_RE_OP: 553 { 554 if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg)) 555 { 556 jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); 557 flags |= JERRY_INIT_SHOW_REGEXP_OPCODES; 558 } 559 break; 560 } 561 case OPT_DEBUG_SERVER: 562 { 563 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 564 { 565 start_debug_server = true; 566 } 567 break; 568 } 569 case OPT_DEBUG_PORT: 570 { 571 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 572 { 573 debug_port = (uint16_t) cli_consume_int (&cli_state); 574 } 575 break; 576 } 577 case OPT_DEBUG_CHANNEL: 578 { 579 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 580 { 581 debug_channel = (char *) cli_consume_string (&cli_state); 582 check_usage (!strcmp (debug_channel, "websocket") || !strcmp (debug_channel, "rawpacket"), 583 argv[0], "Error: invalid value for --debug-channel: ", cli_state.arg); 584 } 585 break; 586 } 587 case OPT_DEBUG_PROTOCOL: 588 { 589 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 590 { 591 debug_protocol = (char *) cli_consume_string (&cli_state); 592 check_usage (!strcmp (debug_protocol, "tcp") || !strcmp (debug_protocol, "serial"), 593 argv[0], "Error: invalid value for --debug-protocol: ", cli_state.arg); 594 } 595 break; 596 } 597 case OPT_DEBUG_SERIAL_CONFIG: 598 { 599 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 600 { 601 debug_serial_config = (char *) cli_consume_string (&cli_state); 602 } 603 break; 604 } 605 case OPT_DEBUGGER_WAIT_SOURCE: 606 { 607 if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg)) 608 { 609 is_wait_mode = true; 610 } 611 break; 612 } 613 case OPT_EXEC_SNAP: 614 { 615 if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg)) 616 { 617 exec_snapshot_file_names[exec_snapshots_count] = cli_consume_string (&cli_state); 618 exec_snapshot_file_indices[exec_snapshots_count++] = 0; 619 } 620 else 621 { 622 cli_consume_string (&cli_state); 623 } 624 break; 625 } 626 case OPT_EXEC_SNAP_FUNC: 627 { 628 if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg)) 629 { 630 exec_snapshot_file_names[exec_snapshots_count] = cli_consume_string (&cli_state); 631 exec_snapshot_file_indices[exec_snapshots_count++] = (uint32_t) cli_consume_int (&cli_state); 632 } 633 else 634 { 635 cli_consume_string (&cli_state); 636 } 637 break; 638 } 639 case OPT_LOG_LEVEL: 640 { 641 long int log_level = cli_consume_int (&cli_state); 642 check_usage (log_level >= 0 && log_level <= 3, 643 argv[0], "Error: invalid value for --log-level: ", cli_state.arg); 644 645 jerry_port_default_set_log_level ((jerry_log_level_t) log_level); 646 break; 647 } 648 case OPT_NO_PROMPT: 649 { 650 no_prompt = true; 651 break; 652 } 653 case CLI_OPT_DEFAULT: 654 { 655 file_names[files_counter++] = cli_consume_string (&cli_state); 656 break; 657 } 658 default: 659 { 660 cli_state.error = "Internal error"; 661 break; 662 } 663 } 664 } 665 666 if (cli_state.error != NULL) 667 { 668 if (cli_state.arg != NULL) 669 { 670 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg); 671 } 672 else 673 { 674 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error); 675 } 676 677 return JERRY_STANDALONE_EXIT_CODE_FAIL; 678 } 679 680 if (files_counter == 0 681 && exec_snapshots_count == 0) 682 { 683 is_repl_mode = true; 684 } 685 686#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) 687 688 jerry_context_t *context_p = jerry_create_context (JERRY_GLOBAL_HEAP_SIZE * 1024, context_alloc, NULL); 689 jerry_port_default_set_current_context (context_p); 690 691#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ 692 693 if (!start_debug_server) 694 { 695 debug_channel = ""; 696 } 697 698 init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config); 699 700 jerry_value_t ret_value = jerry_create_undefined (); 701 702 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC)) 703 { 704 for (int i = 0; i < exec_snapshots_count; i++) 705 { 706 size_t snapshot_size; 707 const uint32_t *snapshot_p = read_file (exec_snapshot_file_names[i], &snapshot_size); 708 709 if (snapshot_p == NULL) 710 { 711 ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Snapshot file load error"); 712 } 713 else 714 { 715 ret_value = jerry_exec_snapshot (snapshot_p, 716 snapshot_size, 717 exec_snapshot_file_indices[i], 718 JERRY_SNAPSHOT_EXEC_COPY_DATA); 719 } 720 721 if (jerry_value_is_error (ret_value)) 722 { 723 break; 724 } 725 } 726 } 727 728 while (true) 729 { 730 731 if (!jerry_value_is_error (ret_value)) 732 { 733 for (int i = 0; i < files_counter; i++) 734 { 735 size_t source_size; 736 const jerry_char_t *source_p = (jerry_char_t *) read_file (file_names[i], &source_size); 737 738 if (source_p == NULL) 739 { 740 ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) "Source file load error"); 741 break; 742 } 743 744 if (!jerry_is_valid_utf8_string (source_p, (jerry_size_t) source_size)) 745 { 746 ret_value = jerry_create_error (JERRY_ERROR_COMMON, (jerry_char_t *) ("Input must be a valid UTF-8 string.")); 747 break; 748 } 749 750 ret_value = jerry_parse ((jerry_char_t *) file_names[i], 751 strlen (file_names[i]), 752 source_p, 753 source_size, 754 JERRY_PARSE_NO_OPTS); 755 756 if (!jerry_value_is_error (ret_value) && !is_parse_only) 757 { 758 jerry_value_t func_val = ret_value; 759 ret_value = jerry_run (func_val); 760 jerry_release_value (func_val); 761 } 762 763 if (jerry_value_is_error (ret_value)) 764 { 765 break; 766 } 767 768 jerry_release_value (ret_value); 769 ret_value = jerry_create_undefined (); 770 } 771 } 772 773 if (is_wait_mode) 774 { 775 is_repl_mode = false; 776 777 if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER)) 778 { 779 while (true) 780 { 781 jerry_debugger_wait_for_source_status_t receive_status; 782 783 do 784 { 785 jerry_value_t run_result; 786 787 receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback, 788 NULL, 789 &run_result); 790 791 if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED) 792 { 793 ret_value = jerry_create_error (JERRY_ERROR_COMMON, 794 (jerry_char_t *) "Connection aborted before source arrived."); 795 } 796 797 if (receive_status == JERRY_DEBUGGER_SOURCE_END) 798 { 799 jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n"); 800 } 801 802 if (jerry_value_is_abort (run_result)) 803 { 804 ret_value = jerry_acquire_value (run_result); 805 } 806 807 jerry_release_value (run_result); 808 } 809 while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED); 810 811 if (receive_status != JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED) 812 { 813 break; 814 } 815 816 init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config); 817 818 ret_value = jerry_create_undefined (); 819 } 820 } 821 822 } 823 824 bool restart = false; 825 826 if (jerry_is_feature_enabled (JERRY_FEATURE_DEBUGGER) && jerry_value_is_abort (ret_value)) 827 { 828 jerry_value_t abort_value = jerry_get_value_from_error (ret_value, false); 829 if (jerry_value_is_string (abort_value)) 830 { 831 static const char restart_str[] = "r353t"; 832 833 jerry_value_t str_val = jerry_value_to_string (abort_value); 834 jerry_size_t str_size = jerry_get_string_size (str_val); 835 836 if (str_size == sizeof (restart_str) - 1) 837 { 838 JERRY_VLA (jerry_char_t, str_buf, str_size); 839 jerry_string_to_char_buffer (str_val, str_buf, str_size); 840 if (memcmp (restart_str, (char *) (str_buf), str_size) == 0) 841 { 842 jerry_release_value (ret_value); 843 restart = true; 844 } 845 } 846 847 jerry_release_value (str_val); 848 } 849 850 jerry_release_value (abort_value); 851 } 852 853 if (!restart) 854 { 855 break; 856 } 857 858 jerry_cleanup (); 859 860 init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config); 861 862 ret_value = jerry_create_undefined (); 863 } 864 865 if (is_repl_mode) 866 { 867 const char *prompt = !no_prompt ? "jerry> " : ""; 868 bool is_done = false; 869 870 while (!is_done) 871 { 872 uint8_t *source_buffer_tail = buffer; 873 size_t len = 0; 874 875 printf ("%s", prompt); 876 877 /* Read a line */ 878 while (true) 879 { 880 if (fread (source_buffer_tail, 1, 1, stdin) != 1) 881 { 882 is_done = true; 883 break; 884 } 885 if (*source_buffer_tail == '\n') 886 { 887 break; 888 } 889 source_buffer_tail ++; 890 len ++; 891 } 892 *source_buffer_tail = 0; 893 894 if (len > 0) 895 { 896 if (!jerry_is_valid_utf8_string (buffer, (jerry_size_t) len)) 897 { 898 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n"); 899 return JERRY_STANDALONE_EXIT_CODE_FAIL; 900 } 901 902 /* Evaluate the line */ 903 jerry_value_t ret_val = jerry_parse (NULL, 904 0, 905 buffer, 906 len, 907 JERRY_PARSE_NO_OPTS); 908 909 if (!jerry_value_is_error (ret_val)) 910 { 911 jerry_value_t func_val = ret_val; 912 ret_val = jerry_run (func_val); 913 jerry_release_value (func_val); 914 } 915 916 if (!jerry_value_is_error (ret_val)) 917 { 918 /* Print return value */ 919 const jerry_value_t args[] = { ret_val }; 920 jerry_value_t ret_val_print = jerryx_handler_print (jerry_create_undefined (), 921 jerry_create_undefined (), 922 args, 923 1); 924 jerry_release_value (ret_val_print); 925 jerry_release_value (ret_val); 926 ret_val = jerry_run_all_enqueued_jobs (); 927 928 if (jerry_value_is_error (ret_val)) 929 { 930 ret_val = jerry_get_value_from_error (ret_val, true); 931 print_unhandled_exception (ret_val); 932 } 933 } 934 else 935 { 936 ret_val = jerry_get_value_from_error (ret_val, true); 937 print_unhandled_exception (ret_val); 938 } 939 940 jerry_release_value (ret_val); 941 } 942 } 943 } 944 945 int ret_code = JERRY_STANDALONE_EXIT_CODE_OK; 946 947 if (jerry_value_is_error (ret_value)) 948 { 949 ret_value = jerry_get_value_from_error (ret_value, true); 950 print_unhandled_exception (ret_value); 951 952 ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; 953 } 954 955 jerry_release_value (ret_value); 956 957 ret_value = jerry_run_all_enqueued_jobs (); 958 959 if (jerry_value_is_error (ret_value)) 960 { 961 ret_value = jerry_get_value_from_error (ret_value, true); 962 print_unhandled_exception (ret_value); 963 ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; 964 } 965 966 jerry_release_value (ret_value); 967 968 if (exit_cb != NULL) 969 { 970 jerry_value_t global = jerry_get_global_object (); 971 jerry_value_t fn_str = jerry_create_string ((jerry_char_t *) exit_cb); 972 jerry_value_t callback_fn = jerry_get_property (global, fn_str); 973 974 jerry_release_value (global); 975 jerry_release_value (fn_str); 976 977 if (jerry_value_is_function (callback_fn)) 978 { 979 jerry_value_t ret_val = jerry_call_function (callback_fn, jerry_create_undefined (), NULL, 0); 980 981 if (jerry_value_is_error (ret_val)) 982 { 983 ret_val = jerry_get_value_from_error (ret_val, true); 984 print_unhandled_exception (ret_val); 985 ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; 986 } 987 988 jerry_release_value (ret_val); 989 } 990 991 jerry_release_value (callback_fn); 992 } 993 994 jerry_cleanup (); 995#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) 996 free (context_p); 997#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */ 998 return ret_code; 999} /* main */ 1000