3 #ifdef MRB_DISABLE_STDIO
4 # error mruby-bin-mruby conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
9 #include <mruby/array.h>
10 #include <mruby/compile.h>
11 #include <mruby/dump.h>
12 #include <mruby/variable.h>
19 mrb_bool check_syntax : 1;
38 usage(const char *name)
40 static const char *const usage_msg[] = {
42 "-b load and execute RiteBinary (mrb) file",
43 "-c check syntax only",
44 "-d set debugging flags (set $DEBUG to true)",
45 "-e 'command' one line of script",
46 "-r library load the library before executing your script",
47 "-v print version number, then run in verbose mode",
48 "--verbose run in verbose mode",
49 "--version print the version",
50 "--copyright print the copyright",
53 const char *const *p = usage_msg;
55 printf("Usage: %s [switches] [programfile] [arguments]\n", name);
57 printf(" %s\n", *p++);
61 options_init(struct options *opts, int argc, char **argv)
65 opts->program = *argv;
70 options_opt(struct options *opts)
72 /* concatenated short options (e.g. `-cv`) */
73 if (*opts->short_opt && *++opts->opt) {
75 opts->short_opt[0] = *opts->opt;
76 opts->short_opt[1] = 0;
77 return opts->short_opt;
80 while (++opts->argv, --opts->argc) {
81 opts->opt = *opts->argv;
83 /* empty || not start with `-` || `-` */
84 if (!opts->opt[0] || opts->opt[0] != '-' || !opts->opt[1]) return NULL;
86 if (opts->opt[1] == '-') {
89 ++opts->argv, --opts->argc;
107 options_arg(struct options *opts)
109 if (*opts->short_opt && opts->opt[1]) {
110 /* concatenated short option and option argument (e.g. `-rLIBRARY`) */
111 *opts->short_opt = 0;
112 return opts->opt + 1;
114 --opts->argc, ++opts->argv;
115 return opts->argc ? *opts->argv : NULL;
119 dup_arg_item(mrb_state *mrb, const char *item)
121 size_t buflen = strlen(item) + 1;
122 char *buf = (char*)mrb_malloc(mrb, buflen);
123 memcpy(buf, item, buflen);
128 parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
130 static const struct _args args_zero = { 0 };
131 struct options opts[1];
132 const char *opt, *item;
135 options_init(opts, argc, argv);
136 while ((opt = options_opt(opts))) {
137 if (strcmp(opt, "b") == 0) {
138 args->mrbfile = TRUE;
140 else if (strcmp(opt, "c") == 0) {
141 args->check_syntax = TRUE;
143 else if (strcmp(opt, "d") == 0) {
146 else if (strcmp(opt, "e") == 0) {
147 if ((item = options_arg(opts))) {
148 if (!args->cmdline) {
149 args->cmdline = dup_arg_item(mrb, item);
155 cmdlinelen = strlen(args->cmdline);
156 itemlen = strlen(item);
158 (char *)mrb_realloc(mrb, args->cmdline, cmdlinelen + itemlen + 2);
159 args->cmdline[cmdlinelen] = '\n';
160 memcpy(args->cmdline + cmdlinelen + 1, item, itemlen + 1);
164 fprintf(stderr, "%s: No code specified for -e\n", opts->program);
168 else if (strcmp(opt, "h") == 0) {
169 usage(opts->program);
172 else if (strcmp(opt, "r") == 0) {
173 if ((item = options_arg(opts))) {
174 if (args->libc == 0) {
175 args->libv = (char**)mrb_malloc(mrb, sizeof(char*));
178 args->libv = (char**)mrb_realloc(mrb, args->libv, sizeof(char*) * (args->libc + 1));
180 args->libv[args->libc++] = dup_arg_item(mrb, item);
183 fprintf(stderr, "%s: No library specified for -r\n", opts->program);
187 else if (strcmp(opt, "v") == 0) {
188 if (!args->verbose) {
189 mrb_show_version(mrb);
190 args->version = TRUE;
192 args->verbose = TRUE;
194 else if (strcmp(opt, "version") == 0) {
195 mrb_show_version(mrb);
198 else if (strcmp(opt, "verbose") == 0) {
199 args->verbose = TRUE;
201 else if (strcmp(opt, "copyright") == 0) {
202 mrb_show_copyright(mrb);
206 fprintf(stderr, "%s: invalid option %s%s (-h will show valid options)\n",
207 opts->program, opt[1] ? "--" : "-", opt);
212 argc = opts->argc; argv = opts->argv;
213 if (args->cmdline == NULL) {
215 if (args->version) exit(EXIT_SUCCESS);
219 args->rfp = strcmp(argv[0], "-") == 0 ?
220 stdin : fopen(argv[0], args->mrbfile ? "rb" : "r");
221 if (args->rfp == NULL) {
222 fprintf(stderr, "%s: Cannot open program file: %s\n", opts->program, argv[0]);
226 args->cmdline = argv[0];
230 args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1));
231 memcpy(args->argv, argv, (argc+1) * sizeof(char*));
238 cleanup(mrb_state *mrb, struct _args *args)
240 if (args->rfp && args->rfp != stdin)
243 mrb_free(mrb, args->cmdline);
244 mrb_free(mrb, args->argv);
246 while (args->libc--) {
247 mrb_free(mrb, args->libv[args->libc]);
249 mrb_free(mrb, args->libv);
255 main(int argc, char **argv)
257 mrb_state *mrb = mrb_open();
267 fprintf(stderr, "%s: Invalid mrb_state, exiting mruby\n", *argv);
271 n = parse_args(mrb, argc, argv, &args);
272 if (n == EXIT_FAILURE || (args.cmdline == NULL && args.rfp == NULL)) {
277 int ai = mrb_gc_arena_save(mrb);
278 ARGV = mrb_ary_new_capa(mrb, args.argc);
279 for (i = 0; i < args.argc; i++) {
280 char* utf8 = mrb_utf8_from_locale(args.argv[i], -1);
282 mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8));
286 mrb_define_global_const(mrb, "ARGV", ARGV);
287 mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
289 c = mrbc_context_new(mrb);
291 c->dump_result = TRUE;
292 if (args.check_syntax)
296 zero_sym = mrb_intern_lit(mrb, "$0");
299 cmdline = args.cmdline ? args.cmdline : "-";
300 mrbc_filename(mrb, c, cmdline);
301 mrb_gv_set(mrb, zero_sym, mrb_str_new_cstr(mrb, cmdline));
304 mrbc_filename(mrb, c, "-e");
305 mrb_gv_set(mrb, zero_sym, mrb_str_new_lit(mrb, "-e"));
309 for (i = 0; i < args.libc; i++) {
310 FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r");
312 fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
313 mrbc_context_free(mrb, c);
318 v = mrb_load_irep_file_cxt(mrb, lfp, c);
321 v = mrb_load_file_cxt(mrb, lfp, c);
328 v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
331 v = mrb_load_file_cxt(mrb, args.rfp, c);
334 char* utf8 = mrb_utf8_from_locale(args.cmdline, -1);
336 v = mrb_load_string_cxt(mrb, utf8, c);
340 mrb_gc_arena_restore(mrb, ai);
341 mrbc_context_free(mrb, c);
343 if (!mrb_undef_p(v)) {
344 mrb_print_error(mrb);
348 else if (args.check_syntax) {