Beispiel #1
0
/*
  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;
}
Beispiel #2
0
/*
  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;
}