Skip to content

Commit

Permalink
Check rawmode option names strictly
Browse files Browse the repository at this point in the history
  • Loading branch information
nobu committed Dec 2, 2022
1 parent abfc6c2 commit aa8fc7e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 10 deletions.
40 changes: 30 additions & 10 deletions ext/io/console/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ getattr(int fd, conmode *t)
#define SET_LAST_ERROR (0)
#endif

static ID id_getc, id_console, id_close, id_min, id_time, id_intr;
static ID id_getc, id_console, id_close;
#if ENABLE_IO_GETPASS
static ID id_gets, id_chomp_bang;
#endif
Expand Down Expand Up @@ -112,18 +112,34 @@ rb_f_send(int argc, VALUE *argv, VALUE recv)
}
#endif

enum rawmode_opt_ids {
kwd_min,
kwd_time,
kwd_intr,
rawmode_opt_id_count
};
static ID rawmode_opt_ids[rawmode_opt_id_count];

typedef struct {
int vmin;
int vtime;
int intr;
} rawmode_arg_t;

#ifndef UNDEF_P
# define UNDEF_P(obj) ((obj) == Qundef)
#endif
#ifndef NIL_OR_UNDEF_P
# define NIL_OR_UNDEF_P(obj) (NIL_P(obj) || UNDEF_P(obj))
#endif

static rawmode_arg_t *
rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *opts)
{
int argc = *argcp;
rawmode_arg_t *optp = NULL;
VALUE vopts = Qnil;
VALUE optvals[rawmode_opt_id_count];
#ifdef RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
argc = rb_scan_args(argc, argv, "*:", NULL, &vopts);
#else
Expand All @@ -138,19 +154,20 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
}
#endif
rb_check_arity(argc, min_argc, max_argc);
if (!NIL_P(vopts)) {
VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
VALUE vtime = rb_hash_aref(vopts, ID2SYM(id_time));
VALUE intr = rb_hash_aref(vopts, ID2SYM(id_intr));
if (rb_get_kwargs(vopts, rawmode_opt_ids,
0, rawmode_opt_id_count, optvals)) {
VALUE vmin = optvals[kwd_min];
VALUE vtime = optvals[kwd_time];
VALUE intr = optvals[kwd_intr];
/* default values by `stty raw` */
opts->vmin = 1;
opts->vtime = 0;
opts->intr = 0;
if (!NIL_P(vmin)) {
if (!NIL_OR_UNDEF_P(vmin)) {
opts->vmin = NUM2INT(vmin);
optp = opts;
}
if (!NIL_P(vtime)) {
if (!NIL_OR_UNDEF_P(vtime)) {
VALUE v10 = INT2FIX(10);
vtime = rb_funcall3(vtime, '*', 1, &v10);
opts->vtime = NUM2INT(vtime);
Expand All @@ -165,6 +182,7 @@ rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *
opts->intr = 0;
optp = opts;
break;
case Qundef:
case Qnil:
break;
default:
Expand Down Expand Up @@ -1633,9 +1651,11 @@ Init_console(void)
#endif
id_console = rb_intern("console");
id_close = rb_intern("close");
id_min = rb_intern("min");
id_time = rb_intern("time");
id_intr = rb_intern("intr");
#define init_rawmode_opt_id(name) \
rawmode_opt_ids[kwd_##name] = rb_intern(#name)
init_rawmode_opt_id(min);
init_rawmode_opt_id(time);
init_rawmode_opt_id(intr);
#ifndef HAVE_RB_F_SEND
id___send__ = rb_intern("__send__");
#endif
Expand Down
8 changes: 8 additions & 0 deletions test/io/console/test_io_console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ def test_failed_path
assert_include(e.message, IO::NULL)
end
end

def test_bad_keyword
assert_raise_with_message(ArgumentError, /unknown keyword:.*bad/) do
File.open(IO::NULL) do |f|
f.raw(bad: 0)
end
end
end
end

defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do
Expand Down

0 comments on commit aa8fc7e

Please sign in to comment.