Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-bin-mrbc / tools / mrbc / mrbc.c
1 #include <mruby.h>
2
3 #ifdef MRB_DISABLE_STDIO
4 # error mruby-bin-mrbc conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb'
5 #endif
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <mruby/compile.h>
10 #include <mruby/dump.h>
11 #include <mruby/proc.h>
12
13 #define RITEBIN_EXT ".mrb"
14 #define C_EXT       ".c"
15
16 struct mrbc_args {
17   int argc;
18   char **argv;
19   int idx;
20   const char *prog;
21   const char *outfile;
22   const char *initname;
23   mrb_bool check_syntax : 1;
24   mrb_bool verbose      : 1;
25   mrb_bool remove_lv    : 1;
26   unsigned int flags    : 4;
27 };
28
29 static void
30 usage(const char *name)
31 {
32   static const char *const usage_msg[] = {
33   "switches:",
34   "-c           check syntax only",
35   "-o<outfile>  place the output into <outfile>",
36   "-v           print version number, then turn on verbose mode",
37   "-g           produce debugging information",
38   "-B<symbol>   binary <symbol> output in C language format",
39   "--remove-lv  remove local variables",
40   "--verbose    run at verbose mode",
41   "--version    print the version",
42   "--copyright  print the copyright",
43   NULL
44   };
45   const char *const *p = usage_msg;
46
47   printf("Usage: %s [switches] programfile\n", name);
48   while (*p)
49     printf("  %s\n", *p++);
50 }
51
52 static char *
53 get_outfilename(mrb_state *mrb, char *infile, const char *ext)
54 {
55   size_t ilen, flen, elen;
56   char *outfile;
57   char *p = NULL;
58
59   ilen = strlen(infile);
60   flen = ilen;
61   if (*ext) {
62     elen = strlen(ext);
63     if ((p = strrchr(infile, '.'))) {
64       ilen = p - infile;
65     }
66     flen += elen;
67   }
68   else {
69     flen = ilen;
70   }
71   outfile = (char*)mrb_malloc(mrb, flen+1);
72   strncpy(outfile, infile, ilen+1);
73   if (p) {
74     strncpy(outfile+ilen, ext, elen+1);
75   }
76
77   return outfile;
78 }
79
80 static int
81 parse_args(mrb_state *mrb, int argc, char **argv, struct mrbc_args *args)
82 {
83   static const struct mrbc_args args_zero = { 0 };
84   int i;
85
86   *args = args_zero;
87   args->argc = argc;
88   args->argv = argv;
89   args->prog = argv[0];
90
91   for (i=1; i<argc; i++) {
92     if (argv[i][0] == '-') {
93       switch ((argv[i])[1]) {
94       case 'o':
95         if (args->outfile) {
96           fprintf(stderr, "%s: an output file is already specified. (%s)\n",
97                   args->prog, args->outfile);
98           return -1;
99         }
100         if (argv[i][2] == '\0' && argv[i+1]) {
101           i++;
102           args->outfile = get_outfilename(mrb, argv[i], "");
103         }
104         else {
105           args->outfile = get_outfilename(mrb, argv[i] + 2, "");
106         }
107         break;
108       case 'B':
109         if (argv[i][2] == '\0' && argv[i+1]) {
110           i++;
111           args->initname = argv[i];
112         }
113         else {
114           args->initname = argv[i]+2;
115         }
116         if (*args->initname == '\0') {
117           fprintf(stderr, "%s: function name is not specified.\n", args->prog);
118           return -1;
119         }
120         break;
121       case 'c':
122         args->check_syntax = TRUE;
123         break;
124       case 'v':
125         if (!args->verbose) mrb_show_version(mrb);
126         args->verbose = TRUE;
127         break;
128       case 'g':
129         args->flags |= DUMP_DEBUG_INFO;
130         break;
131       case 'E':
132       case 'e':
133         fprintf(stderr, "%s: -e/-E option no longer needed.\n", args->prog);
134         break;
135       case 'h':
136         return -1;
137       case '-':
138         if (argv[i][1] == '\n') {
139           return i;
140         }
141         if (strcmp(argv[i] + 2, "version") == 0) {
142           mrb_show_version(mrb);
143           exit(EXIT_SUCCESS);
144         }
145         else if (strcmp(argv[i] + 2, "verbose") == 0) {
146           args->verbose = TRUE;
147           break;
148         }
149         else if (strcmp(argv[i] + 2, "copyright") == 0) {
150           mrb_show_copyright(mrb);
151           exit(EXIT_SUCCESS);
152         }
153         else if (strcmp(argv[i] + 2, "remove-lv") == 0) {
154           args->remove_lv = TRUE;
155           break;
156         }
157         return -1;
158       default:
159         return i;
160       }
161     }
162     else {
163       break;
164     }
165   }
166   return i;
167 }
168
169 static void
170 cleanup(mrb_state *mrb, struct mrbc_args *args)
171 {
172   mrb_free(mrb, (void*)args->outfile);
173   mrb_close(mrb);
174 }
175
176 static int
177 partial_hook(struct mrb_parser_state *p)
178 {
179   mrbc_context *c = p->cxt;
180   struct mrbc_args *args = (struct mrbc_args *)c->partial_data;
181   const char *fn;
182
183   if (p->f) fclose(p->f);
184   if (args->idx >= args->argc) {
185     p->f = NULL;
186     return -1;
187   }
188   fn = args->argv[args->idx++];
189   p->f = fopen(fn, "rb");
190   if (p->f == NULL) {
191     fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, fn);
192     return -1;
193   }
194   mrb_parser_set_filename(p, fn);
195   return 0;
196 }
197
198 static mrb_value
199 load_file(mrb_state *mrb, struct mrbc_args *args)
200 {
201   mrbc_context *c;
202   mrb_value result;
203   char *input = args->argv[args->idx];
204   FILE *infile;
205   mrb_bool need_close = FALSE;
206
207   c = mrbc_context_new(mrb);
208   if (args->verbose)
209     c->dump_result = TRUE;
210   c->no_exec = TRUE;
211   if (input[0] == '-' && input[1] == '\0') {
212     infile = stdin;
213   }
214   else {
215     need_close = TRUE;
216     if ((infile = fopen(input, "rb")) == NULL) {
217       fprintf(stderr, "%s: cannot open program file. (%s)\n", args->prog, input);
218       return mrb_nil_value();
219     }
220   }
221   mrbc_filename(mrb, c, input);
222   args->idx++;
223   if (args->idx < args->argc) {
224     need_close = FALSE;
225     mrbc_partial_hook(mrb, c, partial_hook, (void*)args);
226   }
227
228   result = mrb_load_file_cxt(mrb, infile, c);
229   if (need_close) fclose(infile);
230   mrbc_context_free(mrb, c);
231   if (mrb_undef_p(result)) {
232     return mrb_nil_value();
233   }
234   return result;
235 }
236
237 static int
238 dump_file(mrb_state *mrb, FILE *wfp, const char *outfile, struct RProc *proc, struct mrbc_args *args)
239 {
240   int n = MRB_DUMP_OK;
241   mrb_irep *irep = proc->body.irep;
242
243   if (args->remove_lv) {
244     mrb_irep_remove_lv(mrb, irep);
245   }
246   if (args->initname) {
247     n = mrb_dump_irep_cfunc(mrb, irep, args->flags, wfp, args->initname);
248     if (n == MRB_DUMP_INVALID_ARGUMENT) {
249       fprintf(stderr, "%s: invalid C language symbol name\n", args->initname);
250     }
251   }
252   else {
253     n = mrb_dump_irep_binary(mrb, irep, args->flags, wfp);
254   }
255   if (n != MRB_DUMP_OK) {
256     fprintf(stderr, "%s: error in mrb dump (%s) %d\n", args->prog, outfile, n);
257   }
258   return n;
259 }
260
261 int
262 main(int argc, char **argv)
263 {
264   mrb_state *mrb = mrb_open();
265   int n, result;
266   struct mrbc_args args;
267   FILE *wfp;
268   mrb_value load;
269
270   if (mrb == NULL) {
271     fputs("Invalid mrb_state, exiting mrbc\n", stderr);
272     return EXIT_FAILURE;
273   }
274
275   n = parse_args(mrb, argc, argv, &args);
276   if (n < 0) {
277     cleanup(mrb, &args);
278     usage(argv[0]);
279     return EXIT_FAILURE;
280   }
281   if (n == argc) {
282     fprintf(stderr, "%s: no program file given\n", args.prog);
283     return EXIT_FAILURE;
284   }
285   if (args.outfile == NULL && !args.check_syntax) {
286     if (n + 1 == argc) {
287       args.outfile = get_outfilename(mrb, argv[n], args.initname ? C_EXT : RITEBIN_EXT);
288     }
289     else {
290       fprintf(stderr, "%s: output file should be specified to compile multiple files\n", args.prog);
291       return EXIT_FAILURE;
292     }
293   }
294
295   args.idx = n;
296   load = load_file(mrb, &args);
297   if (mrb_nil_p(load)) {
298     cleanup(mrb, &args);
299     return EXIT_FAILURE;
300   }
301   if (args.check_syntax) {
302     printf("%s:%s:Syntax OK\n", args.prog, argv[n]);
303   }
304
305   if (args.check_syntax) {
306     cleanup(mrb, &args);
307     return EXIT_SUCCESS;
308   }
309
310   if (args.outfile) {
311     if (strcmp("-", args.outfile) == 0) {
312       wfp = stdout;
313     }
314     else if ((wfp = fopen(args.outfile, "wb")) == NULL) {
315       fprintf(stderr, "%s: cannot open output file:(%s)\n", args.prog, args.outfile);
316       return EXIT_FAILURE;
317     }
318   }
319   else {
320     fprintf(stderr, "Output file is required\n");
321     return EXIT_FAILURE;
322   }
323   result = dump_file(mrb, wfp, args.outfile, mrb_proc_ptr(load), &args);
324   fclose(wfp);
325   cleanup(mrb, &args);
326   if (result != MRB_DUMP_OK) {
327     return EXIT_FAILURE;
328   }
329   return EXIT_SUCCESS;
330 }
331
332 void
333 mrb_init_mrblib(mrb_state *mrb)
334 {
335 }
336
337 #ifndef DISABLE_GEMS
338 void
339 mrb_init_mrbgems(mrb_state *mrb)
340 {
341 }
342
343 void
344 mrb_final_mrbgems(mrb_state *mrb)
345 {
346 }
347 #endif