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 "main-utils.h"
28#include "main-options.h"
29
30/**
31 * Temporal buffer size.
32 */
33#define JERRY_BUFFER_SIZE 256u
34
35#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
36/**
37 * The alloc function passed to jerry_create_context
38 */
39static void *
40context_alloc (size_t size,
41 void *cb_data_p)
42{
43 (void) cb_data_p; /* unused */
44 return malloc (size);
45} /* context_alloc */
46#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
47
48int
49main (int argc,
50 char **argv)
51{
52 union
53 {
54 double d;
55 unsigned u;
56 } now = { .d = jerry_port_get_current_time () };
57 srand (now.u);
58
59 JERRY_VLA (main_source_t, sources_p, argc);
60
61 main_args_t arguments;
62 arguments.sources_p = sources_p;
63
64 main_parse_args (argc, argv, &arguments);
65
66#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
67 jerry_context_t *context_p = jerry_create_context (JERRY_GLOBAL_HEAP_SIZE * 1024, context_alloc, NULL);
68 jerry_port_default_set_current_context (context_p);
69#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
70
71restart:
72 main_init_engine (&arguments);
73 int return_code = JERRY_STANDALONE_EXIT_CODE_FAIL;
74 jerry_value_t ret_value;
75
76 for (uint32_t source_index = 0; source_index < arguments.source_count; source_index++)
77 {
78 main_source_t *source_file_p = sources_p + source_index;
79 const char *file_path_p = argv[source_file_p->path_index];
80
81 size_t source_size;
82 uint8_t *source_p = jerry_port_read_source (file_path_p, &source_size);
83
84 if (source_p == NULL)
85 {
86 goto exit;
87 }
88
89 uint32_t parse_opts = JERRY_PARSE_NO_OPTS;
90
91 switch (source_file_p->type)
92 {
93 case SOURCE_SNAPSHOT:
94 {
95 ret_value = jerry_exec_snapshot ((uint32_t *) source_p,
96 source_size,
97 source_file_p->snapshot_index,
98 JERRY_SNAPSHOT_EXEC_COPY_DATA);
99
100 jerry_port_release_source (source_p);
101 break;
102 }
103 case SOURCE_MODULE:
104 {
105 parse_opts = JERRY_PARSE_MODULE;
106 /* FALLTHRU */
107 }
108 default:
109 {
110 assert (source_file_p->type == SOURCE_SCRIPT
111 || source_file_p->type == SOURCE_MODULE);
112
113 if (!jerry_is_valid_utf8_string ((jerry_char_t *) source_p, (jerry_size_t) source_size))
114 {
115 jerry_port_release_source (source_p);
116 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.");
117 goto exit;
118 }
119
120 ret_value = jerry_parse ((jerry_char_t *) file_path_p,
121 strlen (file_path_p),
122 source_p,
123 source_size,
124 parse_opts);
125
126 jerry_port_release_source (source_p);
127
128 if (!jerry_value_is_error (ret_value) && !(arguments.option_flags & OPT_FLAG_PARSE_ONLY))
129 {
130 jerry_value_t func_val = ret_value;
131 ret_value = jerry_run (func_val);
132 jerry_release_value (func_val);
133 }
134
135 break;
136 }
137 }
138
139 if (jerry_value_is_error (ret_value))
140 {
141 if (main_is_value_reset (ret_value))
142 {
143 jerry_cleanup ();
144
145 goto restart;
146 }
147
148 main_print_unhandled_exception (ret_value);
149 goto exit;
150 }
151
152 jerry_release_value (ret_value);
153 }
154
155 if (arguments.option_flags & OPT_FLAG_WAIT_SOURCE)
156 {
157 while (true)
158 {
159 jerry_debugger_wait_for_source_status_t receive_status;
160 receive_status = jerry_debugger_wait_for_client_source (main_wait_for_source_callback,
161 NULL,
162 &ret_value);
163
164 if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED)
165 {
166 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Connection aborted before source arrived.");
167 goto exit;
168 }
169
170 if (receive_status == JERRY_DEBUGGER_SOURCE_END)
171 {
172 jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "No more client source.\n");
173 break;
174 }
175
176 assert (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED
177 || receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
178
179 if (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED
180 || main_is_value_reset (ret_value))
181 {
182 jerry_cleanup ();
183 goto restart;
184 }
185
186 assert (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED);
187 jerry_release_value (ret_value);
188 }
189 }
190 else if (arguments.option_flags & OPT_FLAG_USE_STDIN)
191 {
192 char buffer[JERRY_BUFFER_SIZE];
193 char *source_p = NULL;
194 size_t source_size = 0;
195
196 while (!feof (stdin))
197 {
198 size_t read_bytes = fread (buffer, 1u, JERRY_BUFFER_SIZE, stdin);
199
200 size_t new_size = source_size + read_bytes;
201 source_p = realloc (source_p, new_size);
202
203 memcpy (source_p + source_size, buffer, read_bytes);
204 source_size = new_size;
205 }
206
207 ret_value = jerry_parse (NULL, 0, (jerry_char_t *) source_p, source_size, JERRY_PARSE_NO_OPTS);
208 free (source_p);
209
210 if (jerry_value_is_error (ret_value))
211 {
212 main_print_unhandled_exception (ret_value);
213 goto exit;
214 }
215
216 jerry_value_t func_val = ret_value;
217 ret_value = jerry_run (func_val);
218 jerry_release_value (func_val);
219
220 if (jerry_value_is_error (ret_value))
221 {
222 main_print_unhandled_exception (ret_value);
223 goto exit;
224 }
225
226 jerry_release_value (ret_value);
227 }
228 else if (arguments.source_count == 0)
229 {
230 const char *prompt = (arguments.option_flags & OPT_FLAG_NO_PROMPT) ? "" : "jerry> ";
231 char buffer[JERRY_BUFFER_SIZE];
232
233 while (true)
234 {
235 printf ("%s", prompt);
236 char *str_p = fgets (buffer, JERRY_BUFFER_SIZE, stdin);
237
238 if (str_p == NULL)
239 {
240 printf ("\n");
241 break;
242 }
243
244 size_t len = strlen (str_p);
245
246 if (len == 0)
247 {
248 continue;
249 }
250
251 if (!jerry_is_valid_utf8_string ((jerry_char_t *) str_p, (jerry_size_t) len))
252 {
253 jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Input must be a valid UTF-8 string.\n");
254 continue;
255 }
256
257 ret_value = jerry_parse (NULL, 0, (jerry_char_t *) str_p, len, JERRY_PARSE_NO_OPTS);
258
259 if (jerry_value_is_error (ret_value))
260 {
261 main_print_unhandled_exception (ret_value);
262 continue;
263 }
264
265 jerry_value_t func_val = ret_value;
266 ret_value = jerry_run (func_val);
267 jerry_release_value (func_val);
268
269 if (jerry_value_is_error (ret_value))
270 {
271 main_print_unhandled_exception (ret_value);
272 continue;
273 }
274
275 const jerry_value_t args[] = { ret_value };
276 jerry_value_t ret_val_print = jerryx_handler_print (jerry_create_undefined (),
277 jerry_create_undefined (),
278 args,
279 1);
280 jerry_release_value (ret_val_print);
281 jerry_release_value (ret_value);
282 ret_value = jerry_run_all_enqueued_jobs ();
283
284 if (jerry_value_is_error (ret_value))
285 {
286 main_print_unhandled_exception (ret_value);
287 continue;
288 }
289
290 jerry_release_value (ret_value);
291 }
292 }
293
294 ret_value = jerry_run_all_enqueued_jobs ();
295
296 if (jerry_value_is_error (ret_value))
297 {
298 main_print_unhandled_exception (ret_value);
299 goto exit;
300 }
301
302 jerry_release_value (ret_value);
303
304 if (arguments.exit_cb_name_p != NULL)
305 {
306 jerry_value_t global = jerry_get_global_object ();
307 jerry_value_t name_str = jerry_create_string ((jerry_char_t *) arguments.exit_cb_name_p);
308 jerry_value_t callback_fn = jerry_get_property (global, name_str);
309
310 jerry_release_value (global);
311 jerry_release_value (name_str);
312
313 if (jerry_value_is_function (callback_fn))
314 {
315 ret_value = jerry_call_function (callback_fn, jerry_create_undefined (), NULL, 0);
316
317 if (jerry_value_is_error (ret_value))
318 {
319 main_print_unhandled_exception (ret_value);
320 goto exit;
321 }
322
323 jerry_release_value (ret_value);
324 }
325
326 jerry_release_value (callback_fn);
327 }
328
329 return_code = JERRY_STANDALONE_EXIT_CODE_OK;
330
331exit:
332 jerry_cleanup ();
333
334#if defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1)
335 free (context_p);
336#endif /* defined (JERRY_EXTERNAL_CONTEXT) && (JERRY_EXTERNAL_CONTEXT == 1) */
337
338 return return_code;
339} /* main */
340