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.
This commit is contained in:
dearblue
2021-08-21 15:15:20 +09:00
parent 6415faabaa
commit 66aa184a82
2 changed files with 46 additions and 9 deletions
+7
View File
@@ -911,6 +911,13 @@ MRB_API struct RClass* mrb_define_module_under_id(mrb_state *mrb, struct RClass
* | `:` | keyword args | {mrb_kwargs} const | Get keyword arguments. @see mrb_kwargs |
*
* @see mrb_get_args
*
* Immediately after format specifiers it can add format modifiers:
*
* | char | Notes |
* |:----:|-----------------------------------------------------------------------------------------|
* | `!` | Switch to the alternate mode; The behaviour changes depending on the format specifier |
* | `+` | Request a not frozen object; However, except nil value |
*/
typedef const char *mrb_args_format;
+39 -9
View File
@@ -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;