inline -> __inline
[reactos.git] / reactos / lib / kjs / ksrc / main.c
1 /*
2 * The JS shell
3 * Copyright (c) 1998 New Generation Software (NGS) Oy
4 *
5 * Author: Markku Rossi <mtr@ngs.fi>
6 */
7
8 /*
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * MA 02111-1307, USA
23 */
24
25 /*
26 * $Source: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/kjs/ksrc/main.c,v $
27 * $Id$
28 */
29
30 #if HAVE_CONFIG_H
31 #include "jsconfig.h"
32 #endif
33
34 #include <stdio.h>
35 #include <assert.h>
36
37 #if HAVE_STDC_HEADERS
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41
42 #else /* not HAVE_STDC_HEADERS */
43
44 #if HAVE_STDLIB_H
45 #include <stdlib.h>
46 #endif
47
48 #if HAVE_STRING_H
49 #include <string.h>
50 #endif
51
52 #if HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #endif /* not HAVE_STDC_HEADERS */
57
58 #include "js.h"
59 #include "getopt.h"
60
61 /*
62 * Global variables.
63 */
64
65 char *program;
66
67 /* Options. */
68
69 /*
70 * -a, --annotate-assembler
71 *
72 * Annotate generated assembler listing with the original source code.
73 */
74
75 int annotate_assembler = 0;
76
77 /*
78 * -c, --compile
79 *
80 * Compile all given JavaScript files to byte-code and save the result
81 * to file.
82 */
83
84 int compile = 0;
85
86 /*
87 * -d METHOD, --dispatch=METHOD
88 *
89 * Use byte-code instruction dispatch method METHOD. Possible values are
90 * `switch', `switch-basic' and `jumps'.
91 */
92
93 JSVMDispatchMethod dispatch_method = JS_VM_DISPATCH_JUMPS;
94
95 /*
96 * -e CODE, --eval=CODE
97 *
98 * Evaluate JavaScript code CODE.
99 */
100
101 /*
102 * -E, --events
103 *
104 * Print virtual machine events to the standard error.
105 */
106 int events = 0;
107
108 /*
109 * -f, --file
110 *
111 * Use the next argument as the main source file and pass all
112 * remaining arguments to it through the ARGS array.
113 */
114
115 /*
116 * -g, --debug
117 *
118 * Generate debugging information to the generated byte-code file.
119 */
120 int generate_debug_info = 0;
121
122 /*
123 * -h, --help
124 *
125 * Print short help and exit successfully.
126 */
127
128 /*
129 * -l, --load
130 *
131 * Treat all following arguments, up to option -f / --file, as
132 * byte-code or JavaScript files and execute them. When option -f, --file
133 * is encountered, the next argument is the actual main source file that
134 * is executed with the remaining arguments.
135 */
136
137 /*
138 * -N, --no-compiler
139 *
140 * Do not define compiler in the interpreter. Options makes the
141 * interpreter a pure virtual machine that can't compile any JavaScript
142 * code.
143 */
144
145 int no_compiler = 0;
146
147 /*
148 * -O [LEVEL], --optimize[=LEVEL]
149 *
150 * Optimize at level LEVEL. The default level for batch-compile is 1.
151 * Value 0 disable optimization.
152 */
153
154 int optimize = 1;
155
156 /*
157 * -r OPTION, --secure=OPTIONS
158 *
159 * Turn on security option OPTION.
160 */
161
162 int secure_builtin_file = 0;
163 int secure_builtin_system = 0;
164
165 /*
166 * -s SIZE, --stack-size=SIZE
167 *
168 * Set the virtual machine stack size to SIZE.
169 */
170 unsigned int stack_size = 2048;
171
172 /*
173 * -S, --no-assemble
174 *
175 * Compile al given JavaScript files to JavaScript assembler and save the
176 * result to file.
177 */
178
179 int no_assemble = 0;
180
181 /*
182 * -t, --stacktrace
183 *
184 * Print stack trace on error.
185 */
186
187 int stacktrace_on_error = 0;
188
189 /*
190 * -v, --verbose
191 *
192 * Tell more about what we do.
193 */
194
195 unsigned int verbose = 0;
196
197 /*
198 * -V, --version
199 *
200 * Print version information and exit successfully.
201 */
202
203 /*
204 * -W OPTION, --compiler-option=OPTION
205 *
206 * Set compiler option OPTION.
207 */
208
209 int warn_deprecated = 0;
210 int warn_unused_argument = 0;
211 int warn_unused_variable = 1;
212 int warn_undef = 1;
213 int warn_shadow = 1;
214 int warn_with_clobber = 1;
215 int warn_missing_semicolon = 0;
216 int warn_strict_ecma = 0;
217
218 /*
219 * -x, --executable
220 *
221 * Generate executable byte-code files.
222 */
223 int generate_executable_bc_files = 0;
224
225
226 /*
227 * Static variables.
228 */
229
230 static struct option long_options[] =
231 {
232 {"annotate-assembler", no_argument, 0, 'a'},
233 {"compile", no_argument, 0, 'c'},
234 {"dispatch", required_argument, 0, 'd'},
235 {"eval", required_argument, 0, 'e'},
236 {"events", no_argument, 0, 'E'},
237 {"file", no_argument, 0, 'f'},
238 {"debug", no_argument, 0, 'g'},
239 {"help", no_argument, 0, 'h'},
240 {"load", no_argument, 0, 'l'},
241 {"no-compiler", no_argument, 0, 'N'},
242 {"optimize", optional_argument, 0, 'O'},
243 {"secure", required_argument, 0, 'r'},
244 {"stack-size", required_argument, 0, 's'},
245 {"no-assemble", no_argument, 0, 'S'},
246 {"stacktrace", no_argument, 0, 't'},
247 {"verbose", no_argument, 0, 'v'},
248 {"version", no_argument, 0, 'V'},
249 {"compiler-option", required_argument, 0, 'W'},
250 {"executable", no_argument, 0, 'x'},
251
252 {NULL, 0, 0, 0},
253 };
254
255 /* Compiler options. */
256
257 /* Flags for options. */
258 #define JSC_RUNTIME 0x01
259 #define JSC_WALL 0x02
260 #define JSC_PEDANTIC 0x04
261 #define JSC_LINT 0x08
262
263 static struct
264 {
265 char *name;
266 int *option;
267 unsigned int flags;
268 } compiler_options[] =
269 {
270 {"deprecated", &warn_deprecated, JSC_WALL},
271 {"unused-argument", &warn_unused_argument, JSC_WALL},
272 {"unused-variable", &warn_unused_variable, JSC_WALL},
273 {"undefined", &warn_undef, JSC_RUNTIME},
274 {"shadow", &warn_shadow, JSC_WALL},
275 {"with-clobber", &warn_with_clobber, JSC_WALL},
276 {"missing-semicolon", &warn_missing_semicolon, JSC_PEDANTIC},
277 {"strict-ecma", &warn_strict_ecma, JSC_LINT},
278
279 {NULL, NULL, 0},
280 };
281
282
283 /*
284 * Prototypes for static functions.
285 */
286
287 static void handle_compiler_option (char *name);
288
289 static JSInterpPtr create_interp (void);
290
291 static void usage (void);
292 static void version (void);
293
294 /*
295 * Global functions.
296 */
297
298 int
299 main (int argc, char *argv[])
300 {
301 JSInterpPtr interp = NULL;
302 char *cp;
303 int do_load = 0;
304
305 /* Get program's name. */
306 program = strrchr (argv[0], '/');
307 if (program == NULL)
308 program = argv[0];
309 else
310 program++;
311
312 /* Make getopt_long() to use our modified program name. */
313 argv[0] = program;
314
315 /* Parse arguments. */
316 while (1)
317 {
318 int c;
319 int option_index = 0;
320
321 c = getopt_long (argc, argv, "acd:e:EfghlNO::r:s:StvVW:x",
322 long_options, &option_index);
323 if (c == EOF)
324 break;
325
326 switch (c)
327 {
328 case 'a': /* --annotate-assembler */
329 annotate_assembler = 1;
330 break;
331
332 case 'c': /* --compile */
333 compile = 1;
334 break;
335
336 case 'd': /* --dispatch */
337 if (strcmp (optarg, "switch-basic") == 0)
338 dispatch_method = JS_VM_DISPATCH_SWITCH_BASIC;
339 else if (strcmp (optarg, "switch") == 0)
340 dispatch_method = JS_VM_DISPATCH_SWITCH;
341 else if (strcmp (optarg, "jumps") == 0)
342 dispatch_method = JS_VM_DISPATCH_JUMPS;
343 else
344 {
345 fprintf (stderr, "%s: illegal dispatch method `%s'\n",
346 program, optarg);
347 exit (1);
348 }
349 break;
350
351 case 'e': /* --eval */
352 if (interp == NULL)
353 interp = create_interp ();
354
355 if (!js_eval (interp, optarg))
356 {
357 fprintf (stderr, "%s: eval failed: %s\n", program,
358 js_error_message (interp));
359 exit (1);
360 }
361 break;
362
363 case 'E': /* --events */
364 events = 1;
365 break;
366
367 case 'f': /* --file */
368 if (optind >= argc)
369 {
370 no_argument_for_file:
371 fprintf (stderr, "%s: no arguments after option --file\n",
372 program);
373 exit (1);
374 }
375 goto arguments_done;
376 break;
377
378 case 'g': /* --debug */
379 generate_debug_info = 1;
380 break;
381
382 case 'h': /* --help */
383 usage ();
384 exit (0);
385 break;
386
387 case 'l': /* --load */
388 do_load = 1;
389 goto arguments_done;
390 break;
391
392 case 'N': /* --no-compiler */
393 no_compiler = 1;
394 break;
395
396 case 'O': /* --optimize */
397 if (optarg)
398 optimize = atoi (optarg);
399 break;
400
401 case 'r': /* --secure */
402 if (strcmp (optarg, "file") == 0)
403 secure_builtin_file = 1;
404 else if (strcmp (optarg, "system") == 0)
405 secure_builtin_system = 1;
406 else
407 {
408 fprintf (stderr, "%s: unknown security option `%s'\n",
409 program, optarg);
410 exit (1);
411 }
412 break;
413
414 case 's': /* --stack-size */
415 stack_size = atoi (optarg);
416 break;
417
418 case 'S': /* --no-assemble */
419 no_assemble = 1;
420 break;
421
422 case 't': /* --stacktrace */
423 stacktrace_on_error = 1;
424 break;
425
426 case 'v': /* --verbose */
427 verbose++;
428 break;
429
430 case 'V': /* --version */
431 version ();
432 exit (0);
433 break;
434
435 case 'W': /* --compiler-option */
436 handle_compiler_option (optarg);
437 break;
438
439 case 'x': /* --executable */
440 generate_executable_bc_files = 1;
441 break;
442
443 case '?':
444 fprintf (stderr, "Try `%s --help' for more information.\n",
445 program);
446 exit (1);
447 break;
448
449 default:
450 printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c);
451 if (optarg)
452 printf (" with arg %s", optarg);
453 printf ("\n");
454 abort ();
455 break;
456 }
457 }
458
459 arguments_done:
460
461 interp = create_interp ();
462
463 /* Let's see what we have to do. */
464 if (compile)
465 {
466 char *jscname;
467
468 /*
469 * Treat all remaining arguments as JavaScript files and compile them.
470 */
471
472 for (; optind < argc; optind++)
473 {
474 /* Create name for the byte-code file. */
475
476 jscname = malloc (strlen (argv[optind]) + 5);
477 assert (jscname != NULL);
478 strcpy (jscname, argv[optind]);
479
480 cp = strrchr (jscname, '.');
481 if (cp)
482 strcpy (++cp, "jsc");
483 else
484 strcat (jscname, ".jsc");
485
486 if (verbose)
487 printf ("%s: compiling `%s' to `%s'\n", program,
488 argv[optind], jscname);
489
490 if (!js_compile (interp, argv[optind], NULL, jscname))
491 {
492 fprintf (stderr, "%s\n", js_error_message (interp));
493 exit (1);
494 }
495
496 free (jscname);
497 }
498 }
499 else if (no_assemble)
500 {
501 char *jasname;
502
503 /* Compile argument files to assembler. */
504 for (; optind < argc; optind++)
505 {
506 /* Create name for the assembler file. */
507
508 jasname = malloc (strlen (argv[optind]) + 5);
509 assert (jasname != NULL);
510 strcpy (jasname, argv[optind]);
511
512 cp = strrchr (jasname, '.');
513 if (cp)
514 strcpy (++cp, "jas");
515 else
516 strcat (jasname, ".jas");
517
518 if (verbose)
519 printf ("%s: compiling `%s' to `%s'\n", program,
520 argv[optind], jasname);
521
522 if (!js_compile (interp, argv[optind], jasname, NULL))
523 {
524 fprintf (stderr, "%s\n", js_error_message (interp));
525 exit (1);
526 }
527
528 free (jasname);
529 }
530 }
531 else if (optind < argc)
532 {
533 char *main_file = argv[optind];
534 JSType args;
535 int i;
536
537 /*
538 * Assume that <main_file> contains JavaScript (or byte-code) and
539 * execute it. All the remaining arguments are passed to the
540 * interpreter through the ARGS array.
541 */
542
543 /* Save all remaining arguments to ARGS */
544 js_type_make_array (interp, &args, argc - optind);
545
546 for (i = 0; optind + i < argc; i++)
547 js_type_make_string (interp, &args.u.array->data[i],
548 argv[optind + i], strlen (argv[optind + i]));
549
550 js_set_var (interp, "ARGS", &args);
551
552 if (!js_eval_file (interp, main_file))
553 {
554 fprintf (stderr, "%s: evaluation of file `%s' failed:\n%s\n",
555 program, main_file, js_error_message (interp));
556 exit (1);
557 }
558 }
559
560 js_destroy_interp (interp);
561
562 return 0;
563 }
564
565 \f
566 /*
567 * Static functions.
568 */
569
570 static __inline int
571 is_prefix (char *prefix, char *str)
572 {
573 int i;
574
575 for (i = 0; prefix[i] && str[i] && prefix[i] == str[i]; i++)
576 ;
577 if (!prefix[i])
578 return 1;
579
580 return 0;
581 }
582
583
584 static void
585 handle_compiler_option (char *name)
586 {
587 int i;
588 int value = 1;
589 int nmatches = 0;
590 int did_match = 0;
591
592 if (name[0] == 'n' && name[1] == 'o' && name[2] == '-')
593 {
594 value = 0;
595 name += 3;
596 }
597
598 for (i = 0; compiler_options[i].name; i++)
599 {
600 int was_prefix = 0;
601
602 if ((was_prefix = is_prefix (name, compiler_options[i].name))
603 || (strcmp (name, "runtime") == 0
604 && (compiler_options[i].flags & JSC_RUNTIME))
605 || (strcmp (name, "all") == 0
606 && (compiler_options[i].flags & JSC_WALL))
607 || (strcmp (name, "pedantic") == 0
608 && (compiler_options[i].flags & (JSC_WALL | JSC_PEDANTIC))))
609 {
610 *compiler_options[i].option = value;
611
612 if (was_prefix)
613 nmatches++;
614
615 did_match = 1;
616 }
617 }
618
619 if (!did_match)
620 {
621 fprintf (stderr, "%s: unknown compiler option `-W%s%s'\n", program,
622 value ? "" : "no-", name);
623 exit (1);
624 }
625 if (nmatches > 1)
626 {
627 fprintf (stderr, "%s: ambiguous compiler option `-W%s%s'\n",
628 program, value ? "" : "no-", name);
629 exit (1);
630 }
631 }
632
633
634 static int
635 show_events_hook (int event, void *context)
636 {
637 char *event_name;
638
639 switch (event)
640 {
641 case JS_EVENT_OPERAND_COUNT:
642 event_name = "operand count";
643 break;
644
645 case JS_EVENT_GARBAGE_COLLECT:
646 event_name = "garbage collect";
647 break;
648
649 default:
650 event_name = "unknown";
651 break;
652 }
653
654 fprintf (stderr, "[%s: %s]\n", program, event_name);
655
656 return 0;
657 }
658
659
660 static JSInterpPtr
661 create_interp ()
662 {
663 JSInterpOptions options;
664 JSInterpPtr interp;
665
666 js_init_default_options (&options);
667
668 options.stack_size = stack_size;
669 options.dispatch_method = dispatch_method;
670 options.verbose = verbose;
671
672 options.no_compiler = no_compiler;
673 options.stacktrace_on_error = stacktrace_on_error;
674
675 options.secure_builtin_file = secure_builtin_file;
676 options.secure_builtin_system = secure_builtin_system;
677
678 options.annotate_assembler = annotate_assembler;
679 options.debug_info = generate_debug_info;
680 options.executable_bc_files = generate_executable_bc_files;
681
682 options.warn_unused_argument = warn_unused_argument;
683 options.warn_unused_variable = warn_unused_variable;
684 options.warn_undef = warn_undef;
685 options.warn_shadow = warn_shadow;
686 options.warn_with_clobber = warn_with_clobber;
687 options.warn_missing_semicolon = warn_missing_semicolon;
688 options.warn_strict_ecma = warn_strict_ecma;
689 options.warn_deprecated = warn_deprecated;
690
691 /* As a default, no optimization */
692 options.optimize_peephole = 0;
693 options.optimize_jumps_to_jumps = 0;
694 options.optimize_bc_size = 0;
695 options.optimize_heavy = 0;
696
697 if (optimize >= 1)
698 {
699 options.optimize_peephole = 1;
700 options.optimize_jumps_to_jumps = 1;
701 options.optimize_bc_size = 1;
702 }
703
704 if (optimize >= 2)
705 {
706 options.optimize_heavy = 1;
707 }
708
709 /* Show events? */
710 if (events)
711 {
712 options.hook = show_events_hook;
713 options.hook_operand_count_trigger = 1000000;
714 }
715
716 interp = js_create_interp (&options);
717 if (interp == NULL)
718 {
719 fprintf (stderr, "%s: couldn't create interpreter\n", program);
720 exit (1);
721 }
722
723 /* And finally, define the requested modules. */
724
725 #if WITH_JS
726 if (!js_define_module (interp, js_ext_JS))
727 fprintf (stderr, "%s: warning: couldn't create the JS extension\n",
728 program);
729 #endif
730
731 #if WITH_CURSES
732 if (!js_define_module (interp, js_ext_curses))
733 fprintf (stderr, "%s: warning: couldn't create the curses extension\n",
734 program);
735 #endif
736
737 #if WITH_MD5
738 if (!js_define_module (interp, js_ext_MD5))
739 fprintf (stderr, "%s: warning: couldn't create the MD5 extension\n",
740 program);
741 #endif
742
743 return interp;
744 }
745
746
747 static void
748 usage ()
749 {
750 printf ("\
751 Usage: %s [OPTION]... FILE [ARGUMENT]...\n\
752 Mandatory arguments to long options are mandatory for short options too.\n\
753 -a, --annotate-assembler annotate generated assembler listing with\n\
754 the original source code\n\
755 -c, --compile compile JavaScript input file to byte-code\n\
756 and save the result to the file `FILE.jsc'\n\
757 -d, --dispatch=METHOD use method METHOD for byte-code instruction\n\
758 dispatching\n\
759 -e, --eval=CODE evaluate JavaScript code CODE\n\
760 -E, --events print interpreter events\n\
761 -f, --file evaluate the next argument file and pass\n\
762 all remaining arguments to the interpreter\n\
763 through the ARGS array\n\
764 -g, --debug generate debugging information\n\
765 -h, --help print this help and exit\n\
766 -l, --load evaluate argument files until option `-f',\n\
767 `--file' is encountered\n\
768 -N, --no-compiler do not define compiler to the JavaScript\n\
769 interpreter\n\
770 -O, --optimize[=LEVEL] optimize at level LEVEL\n\
771 -r, --secure=OPTION turn on security option OPTION\n\
772 -s, --stack-size=SIZE set the interpreter stack size to SIZE nodes\n\
773 -S, --assembler compile JavaScript intput file to assembler\n\
774 and save the result to the file `FILE.jas'\n\
775 -t, --stacktrace print stacktrace on error\n\
776 -v, --verbose tell what the interpreter is doing\n\
777 -V, --version print version number\n\
778 -W, --compiler-option=OPTION\n\
779 set compilation option OPTION\n\
780 -x, --executable generate executable byte-code files\n",
781 program);
782
783 printf ("\nReport bugs to mtr@ngs.fi.\n");
784 }
785
786
787 static void
788 version ()
789 {
790 printf ("NGS JavaScript Interpter %s\n\
791 Copyright (C) 1998 New Generation Software (NGS) Oy.\n\
792 NGS JavaScript Interpreter comes with NO WARRANTY, to the extent\n\
793 permitted by law. You may redistribute copies of NGS JavaScript\n\
794 Interpreter under the terms of the GNU Library General Public License.\n\
795 For more information about these matters, see the files named COPYING.\n\
796 ",
797 VERSION);
798 }