/* retrieve arguments from mrb_state. mrb_get_args(mrb, format, ...) returns number of arguments parsed. fortmat specifiers: o: Object [mrb_value] S: String [mrb_value] A: Array [mrb_value] H: Hash [mrb_value] s: String [char*,int] z: String [char*] a: Array [mrb_value*,int] f: Float [mrb_float] i: Integer [mrb_int] n: Symbol [mrb_sym] &: Block [mrb_value] *: rest argument [mrb_value*,int] |: optional */ int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; int i = 0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; int opt = 0; va_start(ap, format); if (argc < 0) { struct RArray *a = mrb_ary_ptr(mrb->stack[1]); argc = a->len; sp = a->ptr; } while ((c = *format++)) { switch (c) { case '|': case '*': case '&': break; default: if (argc <= i && !opt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } } switch (c) { case 'o': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = *sp++; i++; } } break; case 'S': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_str(mrb, *sp++); i++; } } break; case 'A': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_ary(mrb, *sp++); i++; } } break; case 'H': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_hash(mrb, *sp++); i++; } } break; case 's': { mrb_value ss; struct RString *s; char **ps = 0; int *pl = 0; ps = va_arg(ap, char**); pl = va_arg(ap, int*); if (i < argc) { ss = to_str(mrb, *sp++); s = mrb_str_ptr(ss); *ps = s->ptr; *pl = s->len; i++; } } break; case 'z': { mrb_value ss; struct RString *s; char **ps; ps = va_arg(ap, char**); if (i < argc) { ss = to_str(mrb, *sp++); s = mrb_str_ptr(ss); if (strlen(s->ptr) != s->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL"); } *ps = s->ptr; i++; } } break; case 'a': { mrb_value aa; struct RArray *a; mrb_value **pb; int *pl; pb = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (i < argc) { aa = to_ary(mrb, *sp++); a = mrb_ary_ptr(aa); *pb = a->ptr; *pl = a->len; i++; } } break; case 'f': { mrb_float *p; p = va_arg(ap, mrb_float*); if (i < argc) { switch (mrb_type(*sp)) { case MRB_TT_FLOAT: *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: *p = (mrb_float)mrb_fixnum(*sp); break; case MRB_TT_STRING: mrb_raise(mrb, E_TYPE_ERROR, "String can't be coerced into Float"); break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); *p = mrb_float(tmp); } break; } sp++; i++; } } break; case 'i': { mrb_int *p; p = va_arg(ap, mrb_int*); if (i < argc) { switch (mrb_type(*sp)) { case MRB_TT_FIXNUM: *p = mrb_fixnum(*sp); break; case MRB_TT_FLOAT: { mrb_float f = mrb_float(*sp); if (!FIXABLE(f)) { mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); } *p = (mrb_int)f; } break; case MRB_TT_FALSE: *p = 0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); *p = mrb_fixnum(tmp); } break; } sp++; i++; } } break; case 'n': { mrb_sym *symp; symp = va_arg(ap, mrb_sym*); if (i < argc) { mrb_value ss; ss = *sp++; if (mrb_type(ss) == MRB_TT_SYMBOL) { *symp = mrb_symbol(ss); } else { *symp = mrb_intern_str(mrb, to_str(mrb, ss)); } i++; } } break; case '&': { mrb_value *p, *bp; p = va_arg(ap, mrb_value*); if (mrb->ci->argc < 0) { bp = mrb->stack + 2; } else { bp = mrb->stack + mrb->ci->argc + 1; } *p = *bp; } break; case '|': opt = 1; break; case '*': { mrb_value **var; int *pl; var = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { *var = sp; i = argc; } i = argc; sp += *pl; } else { *pl = 0; *var = NULL; } } break; default: mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } if (!c && argc > i) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } va_end(ap); return i; }
/* retrieve arguments from mrb_state. mrb_get_args(mrb, format, ...) returns number of arguments parsed. fortmat specifiers: o: Object [mrb_value] S: String [mrb_value] A: Array [mrb_value] H: Hash [mrb_value] s: String [char*,int] z: String [char*] a: Array [mrb_value*,int] f: Float [mrb_float] i: Integer [mrb_int] &: Block [mrb_value] *: rest argument [mrb_value*,int] |: optional */ int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; int i = 0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; int opt = 0; va_start(ap, format); if (argc < 0) { struct RArray *a = mrb_ary_ptr(mrb->stack[1]); argc = a->len; sp = a->buf; } while ((c = *format++)) { switch (c) { case '|': case '*': case '&': break; default: if (argc <= i) { if (opt) continue; mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } } switch (c) { case 'o': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = *sp; i++; sp++; } break; case 'S': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_str(mrb, *sp); i++; sp++; } break; case 'A': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_ary(mrb, *sp); i++; sp++; } break; case 'H': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_hash(mrb, *sp); i++; sp++; } break; case 's': { mrb_value ss; struct RString *s; char **ps = 0; int *pl = 0; ss = to_str(mrb, *sp); s = mrb_str_ptr(ss); ps = va_arg(ap, char**); *ps = s->buf; pl = va_arg(ap, int*); *pl = s->len; i++; sp++; } break; case 'z': { mrb_value ss; struct RString *s; char **ps; ss = to_str(mrb, *sp); s = mrb_str_ptr(ss); if (strlen(s->buf) != s->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL"); } ps = va_arg(ap, char**); *ps = s->buf; i++; sp++; } break; case 'a': { mrb_value aa; struct RArray *a; mrb_value **pb; int *pl; aa = to_ary(mrb, *sp); a = mrb_ary_ptr(aa); pb = va_arg(ap, mrb_value**); *pb = a->buf; pl = va_arg(ap, int*); *pl = a->len; i++; sp++; } break; case 'f': { mrb_float *p; p = va_arg(ap, mrb_float*); switch (sp->tt) { case MRB_TT_FLOAT: *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: *p = (mrb_float)mrb_fixnum(*sp); break; case MRB_TT_FALSE: *p = 0.0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); *p = mrb_float(tmp); } break; } i++; sp++; } break; case 'i': { mrb_int *p; p = va_arg(ap, mrb_int*); switch (sp->tt) { case MRB_TT_FIXNUM: *p = mrb_fixnum(*sp); break; case MRB_TT_FLOAT: *p = (mrb_int)mrb_float(*sp); break; case MRB_TT_FALSE: *p = 0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); *p = mrb_fixnum(tmp); } break; } i++; sp++; } break; case '&': { mrb_value *p, *bp = mrb->stack + 1; p = va_arg(ap, mrb_value*); if (mrb->ci->argc > 0) { bp += mrb->ci->argc; } *p = *bp; } break; case '|': opt = 1; break; case '*': { mrb_value **var; int *pl; var = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { *var = sp; i = argc; } i = argc; sp += *pl; } else { *pl = 0; *var = NULL; } } break; } } if (!c && argc > i) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } va_end(ap); return i; }