diff options
| author | dearblue <[email protected]> | 2021-08-21 15:15:20 +0900 |
|---|---|---|
| committer | dearblue <[email protected]> | 2021-08-23 21:58:57 +0900 |
| commit | 66aa184a82aeb51ae5ec73f5b38a2523e31305fe (patch) | |
| tree | 40cc6067cb75b4f58e2d1dffd6e4c8644850761a /src/class.c | |
| parent | 6415faabaaa58481d9cc2209792fe2a93e4243ec (diff) | |
| download | mruby-66aa184a82aeb51ae5ec73f5b38a2523e31305fe.tar.gz mruby-66aa184a82aeb51ae5ec73f5b38a2523e31305fe.zip | |
Checks the frozen object with `mrb_get_args()`
This now works with the `+` modifier that can be added after each specifier.
- `nil` is bypassed.
- The `s` and `z` specifiers are received in C as a `const char *`, so adding a `+` modifier will raise an exception.
- The `a` specifier is received in C as `const mrb_value *`, so adding a `+` modifier will raise an exception.
- The `|`, `*`, `&`, `?` and `:` specifiers with `+` modifier raises an exception.
If `!`/`+` exceeds one for each specifier, an exception will occur in the subsequent processing.
This is the same behavior as before.
Diffstat (limited to 'src/class.c')
| -rw-r--r-- | src/class.c | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/src/class.c b/src/class.c index 182ed4510..e7082d5fe 100644 --- a/src/class.c +++ b/src/class.c @@ -902,6 +902,13 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given ':': keyword args [mrb_kwargs const] Get keyword arguments + + format modifiers: + + string note + ---------------------------------------------------------------------------------------------- + !: Switch to the alternate mode; The behaviour changes depending on the specifier + +: Request a not frozen object; However, except nil value */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...) @@ -940,6 +947,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE; goto check_exit; case '!': + case '+': break; case ':': reqkarg = TRUE; @@ -967,14 +975,41 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) i = 0; while ((c = *format++)) { mrb_value *argv = ARGV; - mrb_bool altmode; + mrb_bool altmode = FALSE; + mrb_bool needmodify = FALSE; + + for (; *format; format++) { + switch (*format) { + case '!': + if (altmode) goto modifier_exit; /* not accept for multiple '!' */ + altmode = TRUE; + break; + case '+': + if (needmodify) goto modifier_exit; /* not accept for multiple '+' */ + needmodify = TRUE; + break; + default: + goto modifier_exit; + } + } + modifier_exit: switch (c) { case '|': case '*': case '&': case '?': case ':': + if (needmodify) { + bad_needmodify: + mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong `%c+` modified specifer`", c); + } break; default: if (i < argc) { pickarg = &argv[i++]; + if (needmodify && !mrb_nil_p(*pickarg)) { + if (mrb_immediate_p(*pickarg)) { + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %t", *pickarg); + } + mrb_check_frozen(mrb, mrb_obj_ptr(*pickarg)); + } } else { if (opt) { @@ -987,14 +1022,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; } - if (*format == '!') { - format ++; - altmode = TRUE; - } - else { - altmode = FALSE; - } - switch (c) { case 'o': { @@ -1078,6 +1105,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, const char**); pl = va_arg(ap, mrb_int*); + if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { *ps = NULL; @@ -1096,6 +1124,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps; ps = va_arg(ap, const char**); + if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { *ps = NULL; @@ -1115,6 +1144,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, const mrb_value**); pl = va_arg(ap, mrb_int*); + if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { *pb = 0; |
