forked from xuos/xiuos
				
			
		
			
				
	
	
		
			376 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			376 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Copyright JS Foundation and other contributors, http://js.foundation
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #include <stdbool.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "jerryscript-port.h"
 | |
| #include "jerryscript-port-default.h"
 | |
| 
 | |
| #include "cli.h"
 | |
| #include "main-utils.h"
 | |
| #include "main-options.h"
 | |
| 
 | |
| /**
 | |
|  * Command line option IDs
 | |
|  */
 | |
| typedef enum
 | |
| {
 | |
|   OPT_HELP,
 | |
|   OPT_VERSION,
 | |
|   OPT_MEM_STATS,
 | |
|   OPT_TEST262_OBJECT,
 | |
|   OPT_PARSE_ONLY,
 | |
|   OPT_SHOW_OP,
 | |
|   OPT_SHOW_RE_OP,
 | |
|   OPT_DEBUG_SERVER,
 | |
|   OPT_DEBUG_PORT,
 | |
|   OPT_DEBUG_CHANNEL,
 | |
|   OPT_DEBUG_PROTOCOL,
 | |
|   OPT_DEBUG_SERIAL_CONFIG,
 | |
|   OPT_DEBUGGER_WAIT_SOURCE,
 | |
|   OPT_EXEC_SNAP,
 | |
|   OPT_EXEC_SNAP_FUNC,
 | |
|   OPT_MODULE,
 | |
|   OPT_LOG_LEVEL,
 | |
|   OPT_NO_PROMPT,
 | |
|   OPT_CALL_ON_EXIT,
 | |
|   OPT_USE_STDIN,
 | |
| } main_opt_id_t;
 | |
| 
 | |
| /**
 | |
|  * Command line options
 | |
|  */
 | |
| static const cli_opt_t main_opts[] =
 | |
| {
 | |
|   CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help",
 | |
|                .help = "print this help and exit"),
 | |
|   CLI_OPT_DEF (.id = OPT_VERSION, .opt = "v", .longopt = "version",
 | |
|                .help = "print tool and library version and exit"),
 | |
|   CLI_OPT_DEF (.id = OPT_MEM_STATS, .longopt = "mem-stats",
 | |
|                .help = "dump memory statistics"),
 | |
|   CLI_OPT_DEF (.id = OPT_TEST262_OBJECT, .longopt = "test262-object",
 | |
|                .help = "create test262 object"),
 | |
|   CLI_OPT_DEF (.id = OPT_PARSE_ONLY, .longopt = "parse-only",
 | |
|                .help = "don't execute JS input"),
 | |
|   CLI_OPT_DEF (.id = OPT_SHOW_OP, .longopt = "show-opcodes",
 | |
|                .help = "dump parser byte-code"),
 | |
|   CLI_OPT_DEF (.id = OPT_SHOW_RE_OP, .longopt = "show-regexp-opcodes",
 | |
|                .help = "dump regexp byte-code"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUG_SERVER, .longopt = "start-debug-server",
 | |
|                .help = "start debug server and wait for a connecting client"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUG_PORT, .longopt = "debug-port", .meta = "NUM",
 | |
|                .help = "debug server port (default: 5001)"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUG_CHANNEL, .longopt = "debug-channel", .meta = "[websocket|rawpacket]",
 | |
|                .help = "Specify the debugger transmission channel (default: websocket)"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUG_PROTOCOL, .longopt = "debug-protocol", .meta = "PROTOCOL",
 | |
|                .help = "Specify the transmission protocol over the communication channel (tcp|serial, default: tcp)"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUG_SERIAL_CONFIG, .longopt = "serial-config", .meta = "OPTIONS_STRING",
 | |
|                .help = "Configure parameters for serial port (default: /dev/ttyS0,115200,8,N,1)"),
 | |
|   CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source",
 | |
|                .help = "wait for an executable source from the client"),
 | |
|   CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE",
 | |
|                .help = "execute input snapshot file(s)"),
 | |
|   CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM",
 | |
|                .help = "execute specific function from input snapshot file(s)"),
 | |
|   CLI_OPT_DEF (.id = OPT_MODULE, .opt = "m", .longopt = "module", .meta = "FILE",
 | |
|                .help = "execute module file"),
 | |
|   CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM",
 | |
|                .help = "set log level (0-3)"),
 | |
|   CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt",
 | |
|                .help = "don't print prompt in REPL mode"),
 | |
|   CLI_OPT_DEF (.id = OPT_CALL_ON_EXIT, .longopt = "call-on-exit", .meta = "STRING",
 | |
|                .help = "invoke the specified function when the process is just about to exit"),
 | |
|   CLI_OPT_DEF (.id = OPT_USE_STDIN, .opt = "", .help = "read from standard input"),
 | |
|   CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
 | |
|                .help = "input JS file(s)")
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Check whether a usage-related condition holds. If not, print an error
 | |
|  * message, print the usage, and terminate the application.
 | |
|  */
 | |
| static void
 | |
| check_usage (bool condition, /**< the condition that must hold */
 | |
|              const char *name, /**< name of the application (argv[0]) */
 | |
|              const char *msg, /**< error message to print if condition does not hold */
 | |
|              const char *opt) /**< optional part of the error message */
 | |
| {
 | |
|   if (!condition)
 | |
|   {
 | |
|     jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%s: %s%s\n", name, msg, opt != NULL ? opt : "");
 | |
|     exit (JERRY_STANDALONE_EXIT_CODE_FAIL);
 | |
|   }
 | |
| } /* check_usage */
 | |
| 
 | |
| /**
 | |
|  * Check whether JerryScript has a requested feature enabled or not. If not,
 | |
|  * print a warning message.
 | |
|  *
 | |
|  * @return the status of the feature.
 | |
|  */
 | |
| static bool
 | |
| check_feature (jerry_feature_t feature, /**< feature to check */
 | |
|                const char *option) /**< command line option that triggered this check */
 | |
| {
 | |
|   if (!jerry_is_feature_enabled (feature))
 | |
|   {
 | |
|     jerry_port_default_set_log_level (JERRY_LOG_LEVEL_WARNING);
 | |
|     jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Ignoring '%s' option because this feature is disabled!\n", option);
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| } /* check_feature */
 | |
| 
 | |
| /**
 | |
|  * parse input arguments
 | |
|  */
 | |
| void
 | |
| main_parse_args (int argc, /**< argc */
 | |
|                  char **argv, /**< argv */
 | |
|                  main_args_t *arguments_p) /**< [in/out] arguments reference */
 | |
| {
 | |
|   arguments_p->source_count = 0;
 | |
| 
 | |
|   arguments_p->debug_channel = "websocket";
 | |
|   arguments_p->debug_protocol = "tcp";
 | |
|   arguments_p->debug_serial_config = "/dev/ttyS0,115200,8,N,1";
 | |
|   arguments_p->debug_port = 5001;
 | |
| 
 | |
|   arguments_p->exit_cb_name_p = NULL;
 | |
|   arguments_p->init_flags = JERRY_INIT_EMPTY;
 | |
|   arguments_p->option_flags = OPT_FLAG_EMPTY;
 | |
| 
 | |
|   cli_state_t cli_state = cli_init (main_opts, argc, argv);
 | |
|   for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state))
 | |
|   {
 | |
|     switch (id)
 | |
|     {
 | |
|       case OPT_HELP:
 | |
|       {
 | |
|         cli_help (argv[0], NULL, main_opts);
 | |
|         exit (JERRY_STANDALONE_EXIT_CODE_OK);
 | |
| 
 | |
|         break;
 | |
|       }
 | |
|       case OPT_VERSION:
 | |
|       {
 | |
|         printf ("Version: %d.%d.%d%s\n",
 | |
|                 JERRY_API_MAJOR_VERSION,
 | |
|                 JERRY_API_MINOR_VERSION,
 | |
|                 JERRY_API_PATCH_VERSION,
 | |
|                 JERRY_COMMIT_HASH);
 | |
|         exit (JERRY_STANDALONE_EXIT_CODE_OK);
 | |
| 
 | |
|         break;
 | |
|       }
 | |
|       case OPT_MEM_STATS:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_MEM_STATS, cli_state.arg))
 | |
|         {
 | |
|           jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
 | |
|           arguments_p->init_flags |= JERRY_INIT_MEM_STATS;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_TEST262_OBJECT:
 | |
|       {
 | |
|         arguments_p->option_flags |= OPT_FLAG_TEST262_OBJECT;
 | |
|         break;
 | |
|       }
 | |
|       case OPT_PARSE_ONLY:
 | |
|       {
 | |
|         arguments_p->option_flags |= OPT_FLAG_PARSE_ONLY;
 | |
|         break;
 | |
|       }
 | |
|       case OPT_SHOW_OP:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state.arg))
 | |
|         {
 | |
|           jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
 | |
|           arguments_p->init_flags |= JERRY_INIT_SHOW_OPCODES;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_CALL_ON_EXIT:
 | |
|       {
 | |
|         arguments_p->exit_cb_name_p = cli_consume_string (&cli_state);
 | |
|         break;
 | |
|       }
 | |
|       case OPT_SHOW_RE_OP:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_REGEXP_DUMP, cli_state.arg))
 | |
|         {
 | |
|           jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG);
 | |
|           arguments_p->init_flags |= JERRY_INIT_SHOW_REGEXP_OPCODES;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUG_SERVER:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           arguments_p->option_flags |= OPT_FLAG_DEBUG_SERVER;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUG_PORT:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           arguments_p->debug_port = (uint16_t) cli_consume_int (&cli_state);
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUG_CHANNEL:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           const char *debug_channel = cli_consume_string (&cli_state);
 | |
|           check_usage (!strcmp (debug_channel, "websocket") || !strcmp (debug_channel, "rawpacket"),
 | |
|                        argv[0], "Error: invalid value for --debug-channel: ", cli_state.arg);
 | |
| 
 | |
|           arguments_p->debug_channel = debug_channel;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUG_PROTOCOL:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           const char *debug_protocol = cli_consume_string (&cli_state);
 | |
|           check_usage (!strcmp (debug_protocol, "tcp") || !strcmp (debug_protocol, "serial"),
 | |
|                        argv[0], "Error: invalid value for --debug-protocol: ", cli_state.arg);
 | |
| 
 | |
|           arguments_p->debug_protocol = debug_protocol;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUG_SERIAL_CONFIG:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           arguments_p->debug_serial_config = cli_consume_string (&cli_state);
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_DEBUGGER_WAIT_SOURCE:
 | |
|       {
 | |
|         if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
 | |
|         {
 | |
|           arguments_p->option_flags |= OPT_FLAG_WAIT_SOURCE;
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       case OPT_EXEC_SNAP:
 | |
|       {
 | |
|         const bool is_enabled = check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg);
 | |
|         const uint32_t path_index = cli_consume_path (&cli_state);
 | |
| 
 | |
|         if (is_enabled)
 | |
|         {
 | |
|           main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
 | |
|           arguments_p->source_count++;
 | |
| 
 | |
|           source_p->type = SOURCE_SNAPSHOT;
 | |
|           source_p->path_index = path_index;
 | |
|           source_p->snapshot_index = 0;
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|       }
 | |
|       case OPT_EXEC_SNAP_FUNC:
 | |
|       {
 | |
|         const bool is_enabled = check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg);
 | |
|         const uint32_t path_index = cli_consume_path (&cli_state);
 | |
|         const uint16_t snapshot_index = (uint16_t) cli_consume_int (&cli_state);
 | |
| 
 | |
|         if (is_enabled)
 | |
|         {
 | |
|           main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
 | |
|           arguments_p->source_count++;
 | |
| 
 | |
|           source_p->type = SOURCE_SNAPSHOT;
 | |
|           source_p->path_index = path_index;
 | |
|           source_p->snapshot_index = snapshot_index;
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|       }
 | |
|       case OPT_MODULE:
 | |
|       {
 | |
|         const uint32_t path_index = cli_consume_path (&cli_state);
 | |
| 
 | |
|         main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
 | |
|         arguments_p->source_count++;
 | |
| 
 | |
|         source_p->type = SOURCE_MODULE;
 | |
|         source_p->path_index = path_index;
 | |
|         source_p->snapshot_index = 0;
 | |
| 
 | |
|         break;
 | |
|       }
 | |
|       case OPT_LOG_LEVEL:
 | |
|       {
 | |
|         long int log_level = cli_consume_int (&cli_state);
 | |
|         check_usage (log_level >= 0 && log_level <= 3,
 | |
|                      argv[0], "Error: invalid value for --log-level: ", cli_state.arg);
 | |
| 
 | |
|         jerry_port_default_set_log_level ((jerry_log_level_t) log_level);
 | |
|         break;
 | |
|       }
 | |
|       case OPT_NO_PROMPT:
 | |
|       {
 | |
|         arguments_p->option_flags |= OPT_FLAG_NO_PROMPT;
 | |
|         break;
 | |
|       }
 | |
|       case OPT_USE_STDIN:
 | |
|       {
 | |
|         arguments_p->option_flags |= OPT_FLAG_USE_STDIN;
 | |
|         break;
 | |
|       }
 | |
|       case CLI_OPT_DEFAULT:
 | |
|       {
 | |
|         main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count;
 | |
|         arguments_p->source_count++;
 | |
| 
 | |
|         source_p->type = SOURCE_SCRIPT;
 | |
|         source_p->path_index = cli_consume_path (&cli_state);
 | |
|         break;
 | |
|       }
 | |
|       default:
 | |
|       {
 | |
|         cli_state.error = "Internal error";
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (cli_state.error != NULL)
 | |
|   {
 | |
|     if (cli_state.arg != NULL)
 | |
|     {
 | |
|       jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error);
 | |
|     }
 | |
| 
 | |
|     exit (JERRY_STANDALONE_EXIT_CODE_FAIL);
 | |
|   }
 | |
| } /* main_parse_args */
 |