Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dump.c
Go to the documentation of this file.
1 /*
2 ** dump.c - mruby binary dumper (mrbc binary format)
3 **
4 ** See Copyright Notice in mruby.h
5 */
6 
7 #include <string.h>
8 #include "mruby/dump.h"
9 #include <ctype.h>
10 
11 #include "mruby/string.h"
12 #include "mruby/irep.h"
13 #include "mruby/numeric.h"
14 #include "mruby/debug.h"
15 
16 static size_t get_irep_record_size(mrb_state *mrb, mrb_irep *irep);
17 
18 static uint32_t
19 get_irep_header_size(mrb_state *mrb)
20 {
21  uint32_t size = 0;
22 
23  size += sizeof(uint32_t) * 1;
24  size += sizeof(uint16_t) * 2;
25 
26  return size;
27 }
28 
29 static size_t
30 write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
31 {
32  uint8_t *cur = buf;
33 
34  cur += uint32_to_bin(get_irep_record_size(mrb, irep), cur); /* record size */
35  cur += uint16_to_bin((uint16_t)irep->nlocals, cur); /* number of local variable */
36  cur += uint16_to_bin((uint16_t)irep->nregs, cur); /* number of register variable */
37 
38  return (cur - buf);
39 }
40 
41 
42 static uint32_t
43 get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
44 {
45  uint32_t size = 0;
46  size += sizeof(uint32_t); /* ilen */
47  size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
48  return size;
49 }
50 
51 static int
52 write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
53 {
54  uint8_t *cur = buf;
55  size_t iseq_no;
56 
57  cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
58  for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
59  cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
60  }
61 
62  return (cur - buf);
63 }
64 
65 
66 static size_t
67 get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
68 {
69  size_t size = 0;
70  size_t pool_no;
71  int len;
72  mrb_value str;
73  char buf[32];
74 
75  size += sizeof(uint32_t); /* plen */
76  size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */
77 
78  for (pool_no = 0; pool_no < irep->plen; pool_no++) {
79  int ai = mrb_gc_arena_save(mrb);
80 
81  switch (mrb_type(irep->pool[pool_no])) {
82  case MRB_TT_FIXNUM:
83  str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
84  size += RSTRING_LEN(str);
85  break;
86 
87  case MRB_TT_FLOAT:
88  len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
89  size += len;
90  break;
91 
92  case MRB_TT_STRING:
93  str = mrb_str_to_str(mrb, irep->pool[pool_no]);
94  size += RSTRING_LEN(str);
95  break;
96 
97  default:
98  break;
99  }
100 
101  mrb_gc_arena_restore(mrb, ai);
102  }
103 
104  return size;
105 }
106 
107 static int
108 write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
109 {
110  size_t pool_no;
111  uint8_t *cur = buf;
112  size_t len;
113  mrb_value str;
114  const char *char_ptr;
115  char char_buf[30];
116 
117  cur += uint32_to_bin(irep->plen, cur); /* number of pool */
118 
119  for (pool_no = 0; pool_no < irep->plen; pool_no++) {
120  int ai = mrb_gc_arena_save(mrb);
121 
122  cur += uint8_to_bin(mrb_type(irep->pool[pool_no]), cur); /* data type */
123 
124  switch (mrb_type(irep->pool[pool_no])) {
125  case MRB_TT_FIXNUM:
126  str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
127  char_ptr = RSTRING_PTR(str);
128  len = RSTRING_LEN(str);
129  break;
130 
131  case MRB_TT_FLOAT:
132  len = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
133  char_ptr = &char_buf[0];
134  break;
135 
136  case MRB_TT_STRING:
137  str = irep->pool[pool_no];
138  char_ptr = RSTRING_PTR(str);
139  len = RSTRING_LEN(str);
140  break;
141 
142  default:
143  continue;
144  }
145 
146  cur += uint16_to_bin(len, cur); /* data length */
147  memcpy(cur, char_ptr, len);
148  cur += len;
149 
150  mrb_gc_arena_restore(mrb, ai);
151  }
152 
153  return (int)(cur - buf);
154 }
155 
156 
157 static size_t
158 get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
159 {
160  size_t size = 0;
161  size_t sym_no;
162  size_t len;
163 
164  size += sizeof(uint32_t); /* slen */
165  for (sym_no = 0; sym_no < irep->slen; sym_no++) {
166  size += sizeof(uint16_t); /* snl(n) */
167  if (irep->syms[sym_no] != 0) {
168  mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
169  size += len + 1; /* sn(n) + null char */
170  }
171  }
172 
173  return size;
174 }
175 
176 static int
177 write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
178 {
179  size_t sym_no;
180  uint8_t *cur = buf;
181  const char *name;
182 
183  cur += uint32_to_bin(irep->slen, cur); /* number of symbol */
184 
185  for (sym_no = 0; sym_no < irep->slen; sym_no++) {
186  if (irep->syms[sym_no] != 0) {
187  size_t len;
188 
189  name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
190  if (len > UINT16_MAX) {
192  }
193 
194  cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
195  memcpy(cur, name, len); /* symbol name */
196  cur += (uint16_t)len;
197  *cur++ = '\0';
198  }
199  else {
200  cur += uint16_to_bin(MRB_DUMP_NULL_SYM_LEN, cur); /* length of symbol name */
201  }
202  }
203 
204  return (int)(cur - buf);
205 }
206 
207 
208 
209 static size_t
210 get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
211 {
212  uint32_t size = 0;
213 
214  //size += sizeof(uint16_t); /* rlen */
215  size += get_irep_header_size(mrb);
216  size += get_iseq_block_size(mrb, irep);
217  size += get_pool_block_size(mrb, irep);
218  size += get_syms_block_size(mrb, irep);
219 
220  return size;
221 }
222 
223 static int
224 write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, uint32_t *irep_record_size)
225 {
226  if (irep == NULL) {
227  return MRB_DUMP_INVALID_IREP;
228  }
229 
230  *irep_record_size = get_irep_record_size(mrb, irep);
231  if (*irep_record_size == 0) {
233  }
234 
235  memset(bin, 0, *irep_record_size);
236 
237  //bin += uint16_to_bin(*irep_record_size, bin);
238  bin += write_irep_header(mrb, irep, bin);
239  bin += write_iseq_block(mrb, irep, bin);
240  bin += write_pool_block(mrb, irep, bin);
241  bin += write_syms_block(mrb, irep, bin);
242 
243  return MRB_DUMP_OK;
244 }
245 
246 static size_t
247 mrb_write_eof(mrb_state *mrb, uint8_t *bin)
248 {
249  struct rite_binary_footer footer;
250 
251  memcpy(footer.section_identify, RITE_BINARY_EOF, sizeof(footer.section_identify));
252  uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
253  memcpy(bin, &footer, sizeof(struct rite_binary_footer));
254 
255  return sizeof(struct rite_binary_footer);
256 }
257 
258 
259 static int
260 mrb_write_section_irep_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
261 {
262  struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
263 
264  memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
265  uint32_to_bin(section_size, header->section_size);
266  memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
267  uint16_to_bin(nirep, header->nirep);
268  uint16_to_bin(sirep, header->sirep);
269 
270  return MRB_DUMP_OK;
271 }
272 
273 static int
274 mrb_write_section_irep(mrb_state *mrb, size_t start_index, uint8_t *bin)
275 {
276  int result;
277  size_t irep_no;
278  uint32_t section_size = 0, rlen = 0; /* size of irep record */
279  uint8_t *cur = bin;
280 
281  if (mrb == NULL || start_index >= mrb->irep_len || bin == NULL) {
283  }
284 
285  cur += sizeof(struct rite_section_irep_header);
286  section_size += sizeof(struct rite_section_irep_header);
287 
288  for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
289  result = write_irep_record(mrb, mrb->irep[irep_no], cur, &rlen);
290  if (result != MRB_DUMP_OK) {
291  return result;
292  }
293  cur += rlen;
294  section_size += rlen;
295  }
296 
297  mrb_write_section_irep_header(mrb, section_size, mrb->irep_len - start_index, start_index, bin);
298 
299  return MRB_DUMP_OK;
300 }
301 
302 static int
303 mrb_write_section_lineno_header(mrb_state *mrb, uint32_t section_size, uint16_t nirep, uint16_t sirep, uint8_t *bin)
304 {
305  struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
306 
307  // TODO
308  memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify));
309  uint32_to_bin(section_size, header->section_size);
310  uint16_to_bin(nirep, header->nirep);
311  uint16_to_bin(sirep, header->sirep);
312 
313  return MRB_DUMP_OK;
314 }
315 
316 static size_t
317 get_lineno_record_size(mrb_state *mrb, mrb_irep *irep)
318 {
319  size_t size = 0;
320 
321  size += sizeof(uint32_t); // record size
322  size += sizeof(uint16_t); // filename size
323  if (irep->filename) {
324  size += strlen(irep->filename); // filename
325  }
326  size += sizeof(uint32_t); // niseq
327  if (irep->lines) {
328  size += sizeof(uint16_t) * irep->ilen; // lineno
329  }
330 
331  return size;
332 }
333 
334 static int
335 write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
336 {
337  uint8_t *cur = bin;
338  size_t filename_len = 0, iseq_no;
339 
340  cur += sizeof(uint32_t); /* record size */
341 
342  if (irep->filename) {
343  filename_len = strlen(irep->filename);
344  }
345  cur += uint16_to_bin(filename_len, cur); /* filename size */
346 
347  if (filename_len) {
348  memcpy(cur, irep->filename, filename_len);
349  cur += filename_len; /* filename */
350  }
351 
352  if (irep->lines) {
353  cur += uint32_to_bin(irep->ilen, cur); /* niseq */
354  for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
355  cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */
356  }
357  }
358  else {
359  cur += uint32_to_bin(0, cur); /* niseq */
360  }
361 
362  uint32_to_bin(cur - bin, bin); /* record size */
363 
364  return (cur - bin);
365 }
366 
367 static int
368 mrb_write_section_lineno(mrb_state *mrb, size_t start_index, uint8_t *bin)
369 {
370  size_t irep_no;
371  uint32_t section_size = 0, rlen = 0; /* size of irep record */
372  uint8_t *cur = bin;
373 
374  if (mrb == NULL || start_index >= mrb->irep_len || bin == NULL) {
376  }
377 
378  cur += sizeof(struct rite_section_lineno_header);
379  section_size += sizeof(struct rite_section_lineno_header);
380 
381  for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
382  rlen = write_lineno_record(mrb, mrb->irep[irep_no], cur);
383  cur += rlen;
384  section_size += rlen;
385  }
386 
387  mrb_write_section_lineno_header(mrb, section_size, mrb->irep_len - start_index, start_index, bin);
388 
389  return MRB_DUMP_OK;
390 }
391 
392 static size_t
393 get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
394 {
395  size_t ret = 0;
396  uint32_t f_idx;
397 
398  ret += sizeof(uint32_t); // record size
399  ret += sizeof(uint16_t); // file count
400 
401  for(f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
402  mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
403 
404  ret += sizeof(uint32_t); // position
405  ret += sizeof(uint16_t); // filename index
406 
407  // lines
408  ret += sizeof(uint32_t); // entry count
409  ret += sizeof(uint8_t); // line type
410  switch(file->line_type) {
411  case mrb_debug_line_ary:
412  ret += sizeof(uint16_t) * file->line_entry_count;
413  break;
414 
416  ret += (sizeof(uint32_t) + sizeof(uint16_t)) * file->line_entry_count;
417  break;
418 
419  default: mrb_assert(0); break;
420  }
421  }
422 
423  return ret;
424 }
425 
426 static int
427 find_filename_index(const mrb_sym *ary, size_t ary_len, mrb_sym s)
428 {
429  size_t i;
430 
431  for(i = 0; i < ary_len; ++i) {
432  if(ary[i] == s) { return i; }
433  }
434  return -1;
435 }
436 
437 static int
438 write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, size_t filenames_len)
439 {
440  uint8_t *cur;
441  uint32_t f_idx;
442  size_t ret;
443 
444  cur = bin + sizeof(uint32_t); // skip record size
445  cur += uint16_to_bin(irep->debug_info->flen, cur); // file count
446 
447  for(f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
448  int filename_idx;
449  const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx];
450 
451  // position
452  cur += uint32_to_bin(file->start_pos, cur);
453 
454  // filename index
455  filename_idx = find_filename_index(filenames, filenames_len,
456  file->filename_sym);
457  mrb_assert(filename_idx != -1);
458  cur += uint16_to_bin(filename_idx, cur);
459 
460  // lines
461  cur += uint32_to_bin(file->line_entry_count, cur);
462  cur += uint8_to_bin(file->line_type, cur);
463  switch(file->line_type) {
464  case mrb_debug_line_ary: {
465  size_t l;
466  for(l = 0; l < file->line_entry_count; ++l) {
467  cur += uint16_to_bin(file->line_ary[l], cur);
468  }
469  } break;
470 
472  uint32_t line;
473  for(line = 0; line < file->line_entry_count; ++line) {
474  cur += uint32_to_bin(file->line_flat_map[line].start_pos, cur);
475  cur += uint16_to_bin(file->line_flat_map[line].line, cur);
476  }
477  } break;
478 
479  default: mrb_assert(0); break;
480  }
481  }
482 
483  ret = cur - bin;
484  uint32_to_bin(ret, bin);
485 
486  mrb_assert((cur - bin) == (int)get_debug_record_size(mrb, irep));
487 
488  return ret;
489 }
490 
491 static int
492 mrb_write_section_debug(mrb_state *mrb, size_t start_index, uint8_t *cur)
493 {
494  uint32_t section_size = 0;
495  const uint8_t *bin = cur;
496  struct rite_section_debug_header *header;
497  mrb_sym *filenames;
498  size_t filenames_len;
499  uint8_t *filenames_len_out;
500  size_t irep_i;
501  size_t file_i;
502  uint16_t fn_len;
503  size_t i;
504 
505  if (mrb == NULL || start_index >= mrb->irep_len || cur == NULL) {
507  }
508 
509  header = (struct rite_section_debug_header *)bin;
510  cur += sizeof(struct rite_section_debug_header);
511  section_size += sizeof(struct rite_section_debug_header);
512 
513  // filename table
514  filenames = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym *) * 1);
515  filenames_len = 0;
516  filenames_len_out = cur;
517  cur += sizeof(uint16_t);
518  section_size += sizeof(uint16_t);
519  for (irep_i = start_index; irep_i < mrb->irep_len; ++irep_i) {
520  mrb_irep_debug_info *debug_info = mrb->irep[irep_i]->debug_info;
521 
522  for(file_i = 0; file_i < debug_info->flen; ++file_i) {
523  mrb_irep_debug_info_file *file = debug_info->files[file_i];
524  if(find_filename_index(filenames, filenames_len, file->filename_sym) != -1) continue;
525 
526  // register filename
527  filenames = (mrb_sym*)mrb_realloc(mrb, filenames, sizeof(mrb_sym*) * ++filenames_len);
528  filenames[filenames_len - 1] = file->filename_sym;
529 
530  // filename
531  fn_len = (uint16_t)strlen(file->filename);
532  cur += uint16_to_bin(fn_len, cur);
533  memcpy(cur, file->filename, fn_len);
534  cur += fn_len;
535 
536  section_size += sizeof(uint16_t) + fn_len;
537  }
538  }
539  uint16_to_bin(filenames_len, filenames_len_out);
540 
541  // records
542  for (i = start_index; i < mrb->irep_len; ++i) {
543  uint32_t rlen = write_debug_record(mrb, mrb->irep[i], cur, filenames, filenames_len);
544  cur += rlen;
545  section_size += rlen;
546  }
547 
548  memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
549  uint32_to_bin(section_size, header->section_size);
550  uint16_to_bin(mrb->irep_len - start_index, header->nirep);
551  uint16_to_bin(start_index, header->sirep);
552 
553  mrb_free(mrb, filenames);
554 
555  return MRB_DUMP_OK;
556 }
557 
558 static int
559 write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin)
560 {
561  struct rite_binary_header *header = (struct rite_binary_header *)bin;
562  uint16_t crc;
563  size_t offset;
564 
565  memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify));
566  memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
567  memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
568  memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
569  uint32_to_bin(binary_size, header->binary_size);
570 
571  offset = (&(header->binary_crc[0]) - bin) + sizeof(uint16_t);
572  crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
573  uint16_to_bin(crc, header->binary_crc);
574 
575  return MRB_DUMP_OK;
576 }
577 
578 mrb_bool is_debug_info_defined(mrb_state *mrb, size_t const start_index)
579 {
580  size_t i;
581  for (i = start_index; i < mrb->irep_len; ++i) {
582  if (!mrb->irep[i]->debug_info) { return 0; }
583  }
584  return 1;
585 }
586 
587 static int
588 mrb_dump_irep(mrb_state *mrb, size_t start_index, int debug_info, uint8_t **bin, size_t *bin_size)
589 {
590  int result = MRB_DUMP_GENERAL_FAILURE;
591  size_t section_size = 0;
592  size_t section_irep_size;
593  size_t section_lineno_size = 0;
594  size_t irep_no;
595  uint8_t *cur = NULL;
596 
597  mrb_bool const debug_info_defined = is_debug_info_defined(mrb, start_index);
598 
599  if (mrb == NULL || start_index >= mrb->irep_len) {
600  *bin = NULL;
602  }
603 
604  section_irep_size = sizeof(struct rite_section_irep_header);
605  for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
606  section_irep_size += get_irep_record_size(mrb, mrb->irep[irep_no]);
607  }
608  section_size += section_irep_size;
609 
610  /* DEBUG section size */
611  if (debug_info) {
612  if (debug_info_defined) {
613  mrb_sym *filenames;
614  size_t filenames_len;
615  size_t irep_i;
616  size_t file_i;
617 
618  section_lineno_size += sizeof(struct rite_section_debug_header);
619 
620  // filename table
621  filenames = (mrb_sym *)mrb_malloc(mrb, sizeof(mrb_sym *) + 1);
622  filenames_len = 0;
623  // filename table size
624  section_lineno_size += sizeof(uint16_t);
625  for (irep_i = start_index; irep_i < mrb->irep_len; ++irep_i) {
626  mrb_irep_debug_info *di = mrb->irep[irep_i]->debug_info;
627 
628  for(file_i = 0; file_i < di->flen; ++file_i) {
630  size_t filename_len;
631 
632  file = di->files[file_i];
633  if(find_filename_index(filenames, filenames_len, file->filename_sym) != -1) continue;
634 
635  // register filename
636  filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym*) * ++filenames_len);
637  filenames[filenames_len - 1] = file->filename_sym;
638 
639  // filename
640  mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
641  section_lineno_size += sizeof(uint16_t) + filename_len;
642  }
643  }
644  mrb_free(mrb, filenames);
645 
646  for(irep_no = start_index; irep_no < mrb->irep_len; ++irep_no) {
647  section_lineno_size += get_debug_record_size(mrb, mrb->irep[irep_no]);
648  }
649  section_size += section_lineno_size;
650  }
651  else {
652  section_lineno_size += sizeof(struct rite_section_lineno_header);
653  for (irep_no = start_index; irep_no < mrb->irep_len; irep_no++) {
654  section_lineno_size += get_lineno_record_size(mrb, mrb->irep[irep_no]);
655  }
656  section_size += section_lineno_size;
657  }
658  }
659 
660  *bin_size += sizeof(struct rite_binary_header) + section_size + sizeof(struct rite_binary_footer);
661  cur = *bin = (uint8_t *)mrb_malloc(mrb, *bin_size);
662  if (cur == NULL) {
663  goto error_exit;
664  }
665 
666  cur += sizeof(struct rite_binary_header);
667 
668  result = mrb_write_section_irep(mrb, start_index, cur);
669  if (result != MRB_DUMP_OK) {
670  goto error_exit;
671  }
672 
673  cur += section_irep_size;
674 
675  /* write DEBUG section */
676  if (debug_info) {
677  if(debug_info_defined) {
678  result = mrb_write_section_debug(mrb, start_index, cur);
679  if(result != MRB_DUMP_OK) {
680  goto error_exit;
681  }
682  cur += section_lineno_size;
683  }
684  else {
685  result = mrb_write_section_lineno(mrb, start_index, cur);
686  if (result != MRB_DUMP_OK) {
687  goto error_exit;
688  }
689  cur += section_lineno_size;
690  }
691  }
692 
693  mrb_write_eof(mrb, cur);
694 
695  result = write_rite_binary_header(mrb, *bin_size, *bin);
696 
697 error_exit:
698  if (result != MRB_DUMP_OK) {
699  mrb_free(mrb, *bin);
700  *bin = NULL;
701  }
702  return result;
703 }
704 
705 
706 #ifdef ENABLE_STDIO
707 
708 int
709 mrb_dump_irep_binary(mrb_state *mrb, size_t start_index, int debug_info, FILE* fp)
710 {
711  uint8_t *bin = NULL;
712  size_t bin_size = 0;
713  int result;
714 
715  if (fp == NULL) {
717  }
718 
719  result = mrb_dump_irep(mrb, start_index, debug_info, &bin, &bin_size);
720  if (result == MRB_DUMP_OK) {
721  fwrite(bin, bin_size, 1, fp);
722  }
723 
724  mrb_free(mrb, bin);
725  return result;
726 }
727 
728 static int
729 is_valid_c_symbol_name(const char *name)
730 {
731  const char *c = NULL;
732 
733  if (name == NULL || name[0] == '\0') return 0;
734  if (!ISALPHA(name[0]) && name[0] != '_') return 0;
735 
736  c = &name[1];
737  for (; *c != '\0'; ++c) {
738  if (!ISALNUM(*c) && *c != '_') return 0;
739  }
740 
741  return 1;
742 }
743 
744 int
745 mrb_dump_irep_cfunc(mrb_state *mrb, size_t start_index, int debug_info, FILE *fp, const char *initname)
746 {
747  uint8_t *bin = NULL;
748  size_t bin_size = 0, bin_idx = 0;
749  int result;
750 
751  if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) {
753  }
754 
755  result = mrb_dump_irep(mrb, start_index, debug_info, &bin, &bin_size);
756  if (result == MRB_DUMP_OK) {
757  fprintf(fp, "#include <stdint.h>\n"); // for uint8_t under at least Darwin
758  fprintf(fp, "const uint8_t %s[] = {", initname);
759  while (bin_idx < bin_size) {
760  if (bin_idx % 16 == 0 ) fputs("\n", fp);
761  fprintf(fp, "0x%02x,", bin[bin_idx++]);
762  }
763  fputs("\n};\n", fp);
764  }
765 
766  mrb_free(mrb, bin);
767  return result;
768 }
769 
770 #endif /* ENABLE_STDIO */