Skip to content

Commit a045b6b

Browse files
committed
Allow to mixed and specify *.rb and *.mrb in bin/mruby
It is not decides by the extension. In order to be recognized as a `.mrb` file, the following three points must be satisfied: - File starts with "RITE" - At least `sizeof(struct rite_binary_header)` bytes can be read - `NUL` is included in the first 64 bytes of the file If these are not met, it is judged as a text file and it is processed as a Ruby script. The `bin/mruby -b` switch is still available which treats the given file as a `.mrb` file. New `MRB_API` function: - `include/mruby/compile.h` and `mrbgems/mruby-compiler/core/parse.y` - `mrb_load_detect_file_cxt()` (remove with `MRB_DISABLE_STDIO`) NOTE: - Even script files now always open in binary mode for `bin/mruby`. The `\r\n` is handled by the `nextc()` function already, so there is no problem even on Windows. - The `nextc0()` function in `mrbgems/mruby-compiler/core/parse.y` can now specify a string buffer and a file pointer at the same time. In this case, get it from the string buffer first. This patch includes modifies by comment of #5157.
1 parent 55e1275 commit a045b6b

File tree

6 files changed

+1151
-1025
lines changed

6 files changed

+1151
-1025
lines changed

include/mruby/compile.h

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct mrb_parser_state {
116116
mrb_ast_node *cells;
117117
const char *s, *send;
118118
#ifndef MRB_DISABLE_STDIO
119+
/* If both f and s are non-null, it will be taken preferentially from s until s < send. */
119120
FILE *f;
120121
#endif
121122
mrbc_context *cxt;
@@ -193,6 +194,7 @@ MRB_API mrb_value mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc
193194
#ifndef MRB_DISABLE_STDIO
194195
MRB_API mrb_value mrb_load_file(mrb_state*,FILE*);
195196
MRB_API mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt);
197+
MRB_API mrb_value mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrbc_context *c);
196198
#endif
197199
MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s);
198200
MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, size_t len);

mrbgems/mruby-bin-mruby/bintest/mruby.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def assert_mruby(exp_out, exp_err, exp_success, args)
1919
script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb')
2020
File.write script.path, 'p "ok"'
2121
system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
22-
o = `#{cmd('mruby')} -b #{bin.path}`.strip
22+
o = `#{cmd('mruby')} #{bin.path}`.strip
2323
assert_equal '"ok"', o
2424
end
2525

@@ -33,7 +33,7 @@ def assert_mruby(exp_out, exp_err, exp_success, args)
3333

3434
# .mrb file
3535
`#{cmd('mrbc')} -o "#{bin.path}" "#{script.path}"`
36-
assert_equal "\"#{bin.path}\"", `#{cmd('mruby')} -b "#{bin.path}"`.chomp
36+
assert_equal "\"#{bin.path}\"", `#{cmd('mruby')} "#{bin.path}"`.chomp
3737

3838
# one liner
3939
assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp
@@ -48,7 +48,7 @@ def assert_mruby(exp_out, exp_err, exp_success, args)
4848
script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb')
4949
File.write script.path, 'p [3.21, 2e308.infinite?, -2e308.infinite?]'
5050
system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}"
51-
assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} -b #{bin.path}`.chomp!
51+
assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} #{bin.path}`.chomp!
5252
end
5353

5454
assert '__END__', '8.6' do

mrbgems/mruby-bin-mruby/tools/mruby/mruby.c

+14-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
#include <mruby/variable.h>
1313
#include <mruby/proc.h>
1414

15+
#if defined(_WIN32) || defined(_WIN64)
16+
# include <io.h> /* for setmode */
17+
# include <fcntl.h>
18+
#endif
19+
1520
struct _args {
1621
FILE *rfp;
1722
char *cmdline;
@@ -218,7 +223,7 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
218223
}
219224
else {
220225
args->rfp = strcmp(argv[0], "-") == 0 ?
221-
stdin : fopen(argv[0], args->mrbfile ? "rb" : "r");
226+
stdin : fopen(argv[0], "rb");
222227
if (args->rfp == NULL) {
223228
fprintf(stderr, "%s: Cannot open program file: %s\n", opts->program, argv[0]);
224229
return EXIT_FAILURE;
@@ -228,6 +233,11 @@ parse_args(mrb_state *mrb, int argc, char **argv, struct _args *args)
228233
argc--; argv++;
229234
}
230235
}
236+
#if defined(_WIN32) || defined(_WIN64)
237+
if (args->rfp == stdin) {
238+
setmode(_fileno(stdin), O_BINARY);
239+
}
240+
#endif
231241
args->argv = (char **)mrb_realloc(mrb, args->argv, sizeof(char*) * (argc + 1));
232242
memcpy(args->argv, argv, (argc+1) * sizeof(char*));
233243
args->argc = argc;
@@ -309,7 +319,7 @@ main(int argc, char **argv)
309319
/* Load libraries */
310320
for (i = 0; i < args.libc; i++) {
311321
struct REnv *e;
312-
FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r");
322+
FILE *lfp = fopen(args.libv[i], "rb");
313323
if (lfp == NULL) {
314324
fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
315325
mrbc_context_free(mrb, c);
@@ -320,7 +330,7 @@ main(int argc, char **argv)
320330
v = mrb_load_irep_file_cxt(mrb, lfp, c);
321331
}
322332
else {
323-
v = mrb_load_file_cxt(mrb, lfp, c);
333+
v = mrb_load_detect_file_cxt(mrb, lfp, c);
324334
}
325335
fclose(lfp);
326336
e = mrb->c->cibase->env;
@@ -334,7 +344,7 @@ main(int argc, char **argv)
334344
v = mrb_load_irep_file_cxt(mrb, args.rfp, c);
335345
}
336346
else if (args.rfp) {
337-
v = mrb_load_file_cxt(mrb, args.rfp, c);
347+
v = mrb_load_detect_file_cxt(mrb, args.rfp, c);
338348
}
339349
else {
340350
char* utf8 = mrb_utf8_from_locale(args.cmdline, -1);

mrbgems/mruby-bin-strip/bintest/mruby-strip.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
o = `#{cmd('mruby-strip')} #{compiled1.path}`
3333
assert_equal 0, $?.exitstatus
3434
assert_equal "", o
35-
assert_equal `#{cmd('mruby')} #{script_file.path}`, `#{cmd('mruby')} -b #{compiled1.path}`
35+
assert_equal `#{cmd('mruby')} #{script_file.path}`, `#{cmd('mruby')} #{compiled1.path}`
3636

3737
o = `#{cmd('mruby-strip')} #{compiled1.path} #{compiled2.path}`
3838
assert_equal 0, $?.exitstatus

mrbgems/mruby-compiler/core/parse.y

+71-14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <mruby/error.h>
2222
#include <mruby/throw.h>
2323
#include <mruby/string.h>
24+
#include <mruby/dump.h>
2425
#include "node.h"
2526

2627
#define YYLEX_PARAM p
@@ -4122,20 +4123,20 @@ static inline int
41224123
nextc0(parser_state *p)
41234124
{
41244125
int c;
4125-
#ifndef MRB_DISABLE_STDIO
4126-
if (p->f) {
4127-
if (feof(p->f)) return -1;
4128-
c = fgetc(p->f);
4129-
if (c == EOF) return -1;
4126+
4127+
if (p->s && p->s < p->send) {
4128+
c = (unsigned char)*p->s++;
41304129
}
4131-
else
4130+
else {
4131+
#ifndef MRB_DISABLE_STDIO
4132+
if (p->f) {
4133+
c = fgetc(p->f);
4134+
if (feof(p->f)) return -1;
4135+
}
4136+
else
41324137
#endif
4133-
if (!p->s || p->s >= p->send) {
41344138
return -1;
4135-
}
4136-
else {
4137-
c = (unsigned char)*p->s++;
4138-
}
4139+
}
41394140
return c;
41404141
}
41414142

@@ -6520,19 +6521,26 @@ mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) {
65206521
}
65216522

65226523
#ifndef MRB_DISABLE_STDIO
6523-
MRB_API parser_state*
6524-
mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
6524+
static struct mrb_parser_state *
6525+
mrb_parse_file_continue(mrb_state *mrb, FILE *f, const void *prebuf, size_t prebufsize, mrbc_context *c)
65256526
{
65266527
parser_state *p;
65276528

65286529
p = mrb_parser_new(mrb);
65296530
if (!p) return NULL;
6530-
p->s = p->send = NULL;
6531+
p->s = (const char *)prebuf;
6532+
p->send = (const char *)prebuf + prebufsize;
65316533
p->f = f;
65326534

65336535
mrb_parser_parse(p, c);
65346536
return p;
65356537
}
6538+
6539+
MRB_API parser_state*
6540+
mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
6541+
{
6542+
return mrb_parse_file_continue(mrb, f, NULL, 0, c);
6543+
}
65366544
#endif
65376545

65386546
MRB_API parser_state*
@@ -6629,6 +6637,55 @@ mrb_load_file(mrb_state *mrb, FILE *f)
66296637
{
66306638
return mrb_load_file_cxt(mrb, f, NULL);
66316639
}
6640+
6641+
#define DETECT_SIZE 64
6642+
6643+
/*
6644+
* In order to be recognized as a `.mrb` file, the following three points must be satisfied:
6645+
* - File starts with "RITE"
6646+
* - At least `sizeof(struct rite_binary_header)` bytes can be read
6647+
* - `NUL` is included in the first 64 bytes of the file
6648+
*/
6649+
MRB_API mrb_value
6650+
mrb_load_detect_file_cxt(mrb_state *mrb, FILE *fp, mrbc_context *c)
6651+
{
6652+
union {
6653+
char b[DETECT_SIZE];
6654+
struct rite_binary_header h;
6655+
} leading;
6656+
size_t bufsize;
6657+
6658+
if (mrb == NULL || fp == NULL) {
6659+
return mrb_nil_value();
6660+
}
6661+
6662+
bufsize = fread(leading.b, sizeof(char), sizeof(leading), fp);
6663+
if (bufsize < sizeof(leading.h) ||
6664+
memcmp(leading.h.binary_ident, RITE_BINARY_IDENT, sizeof(leading.h.binary_ident)) != 0 ||
6665+
memchr(leading.b, '\0', bufsize) == NULL) {
6666+
return mrb_load_exec(mrb, mrb_parse_file_continue(mrb, fp, leading.b, bufsize, c), c);
6667+
}
6668+
else {
6669+
size_t binsize;
6670+
uint8_t *bin;
6671+
mrb_value bin_obj = mrb_nil_value(); /* temporary string object */
6672+
mrb_value result;
6673+
6674+
binsize = bin_to_uint32(leading.h.binary_size);
6675+
bin_obj = mrb_str_new(mrb, NULL, binsize);
6676+
bin = (uint8_t *)RSTRING_PTR(bin_obj);
6677+
memcpy(bin, leading.b, bufsize);
6678+
if (binsize > bufsize &&
6679+
fread(bin + bufsize, binsize - bufsize, 1, fp) == 0) {
6680+
binsize = bufsize;
6681+
/* The error is reported by mrb_load_irep_buf_cxt() */
6682+
}
6683+
6684+
result = mrb_load_irep_buf_cxt(mrb, bin, binsize, c);
6685+
if (mrb_string_p(bin_obj)) mrb_str_resize(mrb, bin_obj, 0);
6686+
return result;
6687+
}
6688+
}
66326689
#endif
66336690

66346691
MRB_API mrb_value

0 commit comments

Comments
 (0)