source: EcnlProtoTool/trunk/mruby-2.1.1/src/load.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 17.2 KB
Line 
1/*
2** load.c - mruby binary loader
3**
4** See Copyright Notice in mruby.h
5*/
6
7#include <limits.h>
8#include <stdlib.h>
9#include <string.h>
10#include <math.h>
11#include <mruby/dump.h>
12#include <mruby/irep.h>
13#include <mruby/proc.h>
14#include <mruby/string.h>
15#include <mruby/debug.h>
16#include <mruby/error.h>
17
18#if SIZE_MAX < UINT32_MAX
19# error size_t must be at least 32 bits wide
20#endif
21
22#define FLAG_BYTEORDER_BIG 2
23#define FLAG_BYTEORDER_LIL 4
24#define FLAG_BYTEORDER_NATIVE 8
25#define FLAG_SRC_MALLOC 1
26#define FLAG_SRC_STATIC 0
27
28#define SIZE_ERROR_MUL(nmemb, size) ((size_t)(nmemb) > SIZE_MAX / (size))
29
30static size_t
31skip_padding(const uint8_t *buf)
32{
33 const size_t align = MRB_DUMP_ALIGNMENT;
34 return -(intptr_t)buf & (align-1);
35}
36
37static size_t
38offset_crc_body(void)
39{
40 struct rite_binary_header header;
41 return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc);
42}
43
44#ifndef MRB_WITHOUT_FLOAT
45double mrb_str_len_to_dbl(mrb_state *mrb, const char *s, size_t len, mrb_bool badcheck);
46
47static double
48str_to_double(mrb_state *mrb, const char *p, size_t len)
49{
50 /* `i`, `inf`, `infinity` */
51 if (len > 0 && p[0] == 'i') return INFINITY;
52
53 /* `I`, `-inf`, `-infinity` */
54 if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY;
55 return mrb_str_len_to_dbl(mrb, p, len, TRUE);
56}
57#endif
58
59mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck);
60
61static mrb_irep*
62read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
63{
64 int i;
65 const uint8_t *src = bin;
66 ptrdiff_t diff;
67 uint16_t tt, pool_data_len, snl;
68 int plen;
69 int ai = mrb_gc_arena_save(mrb);
70 mrb_irep *irep = mrb_add_irep(mrb);
71
72 /* skip record size */
73 src += sizeof(uint32_t);
74
75 /* number of local variable */
76 irep->nlocals = bin_to_uint16(src);
77 src += sizeof(uint16_t);
78
79 /* number of register variable */
80 irep->nregs = bin_to_uint16(src);
81 src += sizeof(uint16_t);
82
83 /* number of child irep */
84 irep->rlen = (size_t)bin_to_uint16(src);
85 src += sizeof(uint16_t);
86
87 /* Binary Data Section */
88 /* ISEQ BLOCK */
89 irep->ilen = (uint16_t)bin_to_uint32(src);
90 src += sizeof(uint32_t);
91 src += skip_padding(src);
92
93 if (irep->ilen > 0) {
94 if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
95 return NULL;
96 }
97 if ((flags & FLAG_SRC_MALLOC) == 0 &&
98 (flags & FLAG_BYTEORDER_NATIVE)) {
99 irep->iseq = (mrb_code*)src;
100 src += sizeof(mrb_code) * irep->ilen;
101 irep->flags |= MRB_ISEQ_NO_FREE;
102 }
103 else {
104 size_t data_len = sizeof(mrb_code) * irep->ilen;
105 void *buf = mrb_malloc(mrb, data_len);
106 irep->iseq = (mrb_code *)buf;
107 memcpy(buf, src, data_len);
108 src += data_len;
109 }
110 }
111
112 /* POOL BLOCK */
113 plen = bin_to_uint32(src); /* number of pool */
114 src += sizeof(uint32_t);
115 if (plen > 0) {
116 if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
117 return NULL;
118 }
119 irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen);
120
121 for (i = 0; i < plen; i++) {
122 const char *s;
123 mrb_bool st = (flags & FLAG_SRC_MALLOC)==0;
124
125 tt = *src++; /* pool TT */
126 pool_data_len = bin_to_uint16(src); /* pool data length */
127 src += sizeof(uint16_t);
128 s = (const char*)src;
129 src += pool_data_len;
130 switch (tt) { /* pool data */
131 case IREP_TT_FIXNUM: {
132 mrb_value num = mrb_str_len_to_inum(mrb, s, pool_data_len, 10, FALSE);
133#ifdef MRB_WITHOUT_FLOAT
134 irep->pool[i] = num;
135#else
136 irep->pool[i] = mrb_float_p(num)? mrb_float_pool(mrb, mrb_float(num)) : num;
137#endif
138 }
139 break;
140
141#ifndef MRB_WITHOUT_FLOAT
142 case IREP_TT_FLOAT:
143 irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s, pool_data_len));
144 break;
145#endif
146
147 case IREP_TT_STRING:
148 irep->pool[i] = mrb_str_pool(mrb, s, pool_data_len, st);
149 break;
150
151 default:
152 /* should not happen */
153 irep->pool[i] = mrb_nil_value();
154 break;
155 }
156 irep->plen++;
157 mrb_gc_arena_restore(mrb, ai);
158 }
159 }
160
161 /* SYMS BLOCK */
162 irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */
163 src += sizeof(uint32_t);
164 if (irep->slen > 0) {
165 if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
166 return NULL;
167 }
168 irep->syms = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
169
170 for (i = 0; i < irep->slen; i++) {
171 snl = bin_to_uint16(src); /* symbol name length */
172 src += sizeof(uint16_t);
173
174 if (snl == MRB_DUMP_NULL_SYM_LEN) {
175 irep->syms[i] = 0;
176 continue;
177 }
178
179 if (flags & FLAG_SRC_MALLOC) {
180 irep->syms[i] = mrb_intern(mrb, (char *)src, snl);
181 }
182 else {
183 irep->syms[i] = mrb_intern_static(mrb, (char *)src, snl);
184 }
185 src += snl + 1;
186
187 mrb_gc_arena_restore(mrb, ai);
188 }
189 }
190
191 irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*irep->rlen);
192
193 diff = src - bin;
194 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
195 *len = (size_t)diff;
196
197 return irep;
198}
199
200static mrb_irep*
201read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags)
202{
203 mrb_irep *irep = read_irep_record_1(mrb, bin, len, flags);
204 int i;
205
206 if (irep == NULL) {
207 return NULL;
208 }
209
210 bin += *len;
211 for (i=0; i<irep->rlen; i++) {
212 size_t rlen;
213
214 irep->reps[i] = read_irep_record(mrb, bin, &rlen, flags);
215 if (irep->reps[i] == NULL) {
216 return NULL;
217 }
218 bin += rlen;
219 *len += rlen;
220 }
221 return irep;
222}
223
224static mrb_irep*
225read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags)
226{
227 size_t len;
228
229 bin += sizeof(struct rite_section_irep_header);
230 return read_irep_record(mrb, bin, &len, flags);
231}
232
233static int
234read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
235{
236 const uint8_t *bin = start;
237 ptrdiff_t diff;
238 size_t record_size;
239 uint16_t f_idx;
240 int i;
241
242 if (irep->debug_info) { return MRB_DUMP_INVALID_IREP; }
243
244 irep->debug_info = (mrb_irep_debug_info*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info));
245 irep->debug_info->pc_count = (uint32_t)irep->ilen;
246
247 record_size = (size_t)bin_to_uint32(bin);
248 bin += sizeof(uint32_t);
249
250 irep->debug_info->flen = bin_to_uint16(bin);
251 irep->debug_info->files = (mrb_irep_debug_info_file**)mrb_malloc(mrb, sizeof(mrb_irep_debug_info*) * irep->debug_info->flen);
252 bin += sizeof(uint16_t);
253
254 for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
255 mrb_irep_debug_info_file *file;
256 uint16_t filename_idx;
257
258 file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file));
259 irep->debug_info->files[f_idx] = file;
260
261 file->start_pos = bin_to_uint32(bin);
262 bin += sizeof(uint32_t);
263
264 /* filename */
265 filename_idx = bin_to_uint16(bin);
266 bin += sizeof(uint16_t);
267 mrb_assert(filename_idx < filenames_len);
268 file->filename_sym = filenames[filename_idx];
269
270 file->line_entry_count = bin_to_uint32(bin);
271 bin += sizeof(uint32_t);
272 file->line_type = (mrb_debug_line_type)bin_to_uint8(bin);
273 bin += sizeof(uint8_t);
274 switch (file->line_type) {
275 case mrb_debug_line_ary: {
276 uint32_t l;
277
278 file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count));
279 for (l = 0; l < file->line_entry_count; ++l) {
280 file->lines.ary[l] = bin_to_uint16(bin);
281 bin += sizeof(uint16_t);
282 }
283 } break;
284
285 case mrb_debug_line_flat_map: {
286 uint32_t l;
287
288 file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(
289 mrb, sizeof(mrb_irep_debug_info_line) * (size_t)(file->line_entry_count));
290 for (l = 0; l < file->line_entry_count; ++l) {
291 file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
292 bin += sizeof(uint32_t);
293 file->lines.flat_map[l].line = bin_to_uint16(bin);
294 bin += sizeof(uint16_t);
295 }
296 } break;
297
298 default: return MRB_DUMP_GENERAL_FAILURE;
299 }
300 }
301
302 diff = bin - start;
303 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
304
305 if (record_size != (size_t)diff) {
306 return MRB_DUMP_GENERAL_FAILURE;
307 }
308
309 for (i = 0; i < irep->rlen; i++) {
310 size_t len;
311 int ret;
312
313 ret = read_debug_record(mrb, bin, irep->reps[i], &len, filenames, filenames_len);
314 if (ret != MRB_DUMP_OK) return ret;
315 bin += len;
316 }
317
318 diff = bin - start;
319 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
320 *record_len = (size_t)diff;
321
322 return MRB_DUMP_OK;
323}
324
325static int
326read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
327{
328 const uint8_t *bin;
329 ptrdiff_t diff;
330 struct rite_section_debug_header *header;
331 uint16_t i;
332 size_t len = 0;
333 int result;
334 uint16_t filenames_len;
335 mrb_sym *filenames;
336
337 bin = start;
338 header = (struct rite_section_debug_header *)bin;
339 bin += sizeof(struct rite_section_debug_header);
340
341 filenames_len = bin_to_uint16(bin);
342 bin += sizeof(uint16_t);
343 filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)filenames_len);
344 for (i = 0; i < filenames_len; ++i) {
345 uint16_t f_len = bin_to_uint16(bin);
346 bin += sizeof(uint16_t);
347 if (flags & FLAG_SRC_MALLOC) {
348 filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
349 }
350 else {
351 filenames[i] = mrb_intern_static(mrb, (const char *)bin, (size_t)f_len);
352 }
353 bin += f_len;
354 }
355
356 result = read_debug_record(mrb, bin, irep, &len, filenames, filenames_len);
357 if (result != MRB_DUMP_OK) goto debug_exit;
358
359 bin += len;
360 diff = bin - start;
361 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
362 if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
363 result = MRB_DUMP_GENERAL_FAILURE;
364 }
365
366debug_exit:
367 mrb_free(mrb, filenames);
368 return result;
369}
370
371static int
372read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *record_len, mrb_sym const *syms, uint32_t syms_len)
373{
374 const uint8_t *bin = start;
375 ptrdiff_t diff;
376 int i;
377
378 irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (irep->nlocals - 1));
379
380 for (i = 0; i + 1< irep->nlocals; ++i) {
381 uint16_t const sym_idx = bin_to_uint16(bin);
382 bin += sizeof(uint16_t);
383 if (sym_idx == RITE_LV_NULL_MARK) {
384 irep->lv[i].name = 0;
385 irep->lv[i].r = 0;
386 }
387 else {
388 if (sym_idx >= syms_len) {
389 return MRB_DUMP_GENERAL_FAILURE;
390 }
391 irep->lv[i].name = syms[sym_idx];
392
393 irep->lv[i].r = bin_to_uint16(bin);
394 }
395 bin += sizeof(uint16_t);
396 }
397
398 for (i = 0; i < irep->rlen; ++i) {
399 size_t len;
400 int ret;
401
402 ret = read_lv_record(mrb, bin, irep->reps[i], &len, syms, syms_len);
403 if (ret != MRB_DUMP_OK) return ret;
404 bin += len;
405 }
406
407 diff = bin - start;
408 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
409 *record_len = (size_t)diff;
410
411 return MRB_DUMP_OK;
412}
413
414static int
415read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
416{
417 const uint8_t *bin;
418 ptrdiff_t diff;
419 struct rite_section_lv_header const *header;
420 uint32_t i;
421 size_t len = 0;
422 int result;
423 uint32_t syms_len;
424 mrb_sym *syms;
425 mrb_sym (*intern_func)(mrb_state*, const char*, size_t) =
426 (flags & FLAG_SRC_MALLOC)? mrb_intern : mrb_intern_static;
427
428 bin = start;
429 header = (struct rite_section_lv_header const*)bin;
430 bin += sizeof(struct rite_section_lv_header);
431
432 syms_len = bin_to_uint32(bin);
433 bin += sizeof(uint32_t);
434 syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (size_t)syms_len);
435 for (i = 0; i < syms_len; ++i) {
436 uint16_t const str_len = bin_to_uint16(bin);
437 bin += sizeof(uint16_t);
438
439 syms[i] = intern_func(mrb, (const char*)bin, str_len);
440 bin += str_len;
441 }
442
443 result = read_lv_record(mrb, bin, irep, &len, syms, syms_len);
444 if (result != MRB_DUMP_OK) goto lv_exit;
445
446 bin += len;
447 diff = bin - start;
448 mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
449 if ((uint32_t)diff != bin_to_uint32(header->section_size)) {
450 result = MRB_DUMP_GENERAL_FAILURE;
451 }
452
453lv_exit:
454 mrb_free(mrb, syms);
455 return result;
456}
457
458static int
459read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags)
460{
461 const struct rite_binary_header *header = (const struct rite_binary_header *)bin;
462
463 if (bufsize < sizeof(struct rite_binary_header)) {
464 return MRB_DUMP_READ_FAULT;
465 }
466
467 if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) {
468 if (bigendian_p())
469 *flags |= FLAG_BYTEORDER_NATIVE;
470 else
471 *flags |= FLAG_BYTEORDER_BIG;
472 }
473 else if (memcmp(header->binary_ident, RITE_BINARY_IDENT_LIL, sizeof(header->binary_ident)) == 0) {
474 if (bigendian_p())
475 *flags |= FLAG_BYTEORDER_LIL;
476 else
477 *flags |= FLAG_BYTEORDER_NATIVE;
478 }
479 else {
480 return MRB_DUMP_INVALID_FILE_HEADER;
481 }
482
483 if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) {
484 return MRB_DUMP_INVALID_FILE_HEADER;
485 }
486
487 if (crc) {
488 *crc = bin_to_uint16(header->binary_crc);
489 }
490 *bin_size = (size_t)bin_to_uint32(header->binary_size);
491
492 if (bufsize < *bin_size) {
493 return MRB_DUMP_READ_FAULT;
494 }
495
496 return MRB_DUMP_OK;
497}
498
499static mrb_irep*
500read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags)
501{
502 int result;
503 mrb_irep *irep = NULL;
504 const struct rite_section_header *section_header;
505 uint16_t crc;
506 size_t bin_size = 0;
507 size_t n;
508
509 if ((mrb == NULL) || (bin == NULL)) {
510 return NULL;
511 }
512
513 result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags);
514 if (result != MRB_DUMP_OK) {
515 return NULL;
516 }
517
518 n = offset_crc_body();
519 if (crc != calc_crc_16_ccitt(bin + n, bin_size - n, 0)) {
520 return NULL;
521 }
522
523 bin += sizeof(struct rite_binary_header);
524 do {
525 section_header = (const struct rite_section_header *)bin;
526 if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) {
527 irep = read_section_irep(mrb, bin, flags);
528 if (!irep) return NULL;
529 }
530 else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) {
531 if (!irep) return NULL; /* corrupted data */
532 result = read_section_debug(mrb, bin, irep, flags);
533 if (result < MRB_DUMP_OK) {
534 return NULL;
535 }
536 }
537 else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) {
538 if (!irep) return NULL;
539 result = read_section_lv(mrb, bin, irep, flags);
540 if (result < MRB_DUMP_OK) {
541 return NULL;
542 }
543 }
544 bin += bin_to_uint32(section_header->section_size);
545 } while (memcmp(section_header->section_ident, RITE_BINARY_EOF, sizeof(section_header->section_ident)) != 0);
546
547 return irep;
548}
549
550mrb_irep*
551mrb_read_irep(mrb_state *mrb, const uint8_t *bin)
552{
553#if defined(MRB_USE_LINK_TIME_RO_DATA_P) || defined(MRB_USE_CUSTOM_RO_DATA_P)
554 uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
555#else
556 uint8_t flags = FLAG_SRC_STATIC;
557#endif
558
559 return read_irep(mrb, bin, (size_t)-1, flags);
560}
561
562MRB_API mrb_irep*
563mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize)
564{
565 return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC);
566}
567
568void mrb_exc_set(mrb_state *mrb, mrb_value exc);
569
570static void
571irep_error(mrb_state *mrb)
572{
573 mrb_exc_set(mrb, mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "irep load error"));
574}
575
576void mrb_codedump_all(mrb_state*, struct RProc*);
577
578static mrb_value
579load_irep(mrb_state *mrb, mrb_irep *irep, mrbc_context *c)
580{
581 struct RProc *proc;
582
583 if (!irep) {
584 irep_error(mrb);
585 return mrb_nil_value();
586 }
587 proc = mrb_proc_new(mrb, irep);
588 proc->c = NULL;
589 mrb_irep_decref(mrb, irep);
590 if (c && c->dump_result) mrb_codedump_all(mrb, proc);
591 if (c && c->no_exec) return mrb_obj_value(proc);
592 return mrb_top_run(mrb, proc, mrb_top_self(mrb), 0);
593}
594
595MRB_API mrb_value
596mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c)
597{
598 return load_irep(mrb, mrb_read_irep(mrb, bin), c);
599}
600
601MRB_API mrb_value
602mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c)
603{
604 return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c);
605}
606
607MRB_API mrb_value
608mrb_load_irep(mrb_state *mrb, const uint8_t *bin)
609{
610 return mrb_load_irep_cxt(mrb, bin, NULL);
611}
612
613MRB_API mrb_value
614mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize)
615{
616 return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL);
617}
618
619#ifndef MRB_DISABLE_STDIO
620
621mrb_irep*
622mrb_read_irep_file(mrb_state *mrb, FILE* fp)
623{
624 mrb_irep *irep = NULL;
625 uint8_t *buf;
626 const size_t header_size = sizeof(struct rite_binary_header);
627 size_t buf_size = 0;
628 uint8_t flags = 0;
629 int result;
630
631 if ((mrb == NULL) || (fp == NULL)) {
632 return NULL;
633 }
634
635 buf = (uint8_t*)mrb_malloc(mrb, header_size);
636 if (fread(buf, header_size, 1, fp) == 0) {
637 goto irep_exit;
638 }
639 result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags);
640 if (result != MRB_DUMP_OK || buf_size <= header_size) {
641 goto irep_exit;
642 }
643
644 buf = (uint8_t*)mrb_realloc(mrb, buf, buf_size);
645 if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) {
646 goto irep_exit;
647 }
648 irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC);
649
650irep_exit:
651 mrb_free(mrb, buf);
652 return irep;
653}
654
655MRB_API mrb_value
656mrb_load_irep_file_cxt(mrb_state *mrb, FILE* fp, mrbc_context *c)
657{
658 return load_irep(mrb, mrb_read_irep_file(mrb, fp), c);
659}
660
661MRB_API mrb_value
662mrb_load_irep_file(mrb_state *mrb, FILE* fp)
663{
664 return mrb_load_irep_file_cxt(mrb, fp, NULL);
665}
666#endif /* MRB_DISABLE_STDIO */
Note: See TracBrowser for help on using the repository browser.