rewrite pic_get_args to check nparams first

This commit is contained in:
Sunrin SHIMURA (keen) 2015-02-02 18:30:14 +00:00
parent 40dc4a0e9c
commit e2f10ba3ad
1 changed files with 175 additions and 210 deletions

View File

@ -58,64 +58,78 @@ int
pic_get_args(pic_state *pic, const char *format, ...) pic_get_args(pic_state *pic, const char *format, ...)
{ {
char c; char c;
int i = 1, argc = pic->ci->argc; int paramc, optc, ext = 0;
int i , argc = pic->ci->argc;
va_list ap; va_list ap;
bool opt = false; bool rest = false;
va_start(ap, format); /* check nparams first */
while ((c = *format++)) { for (paramc = 0; format[paramc]; paramc++) {
switch (c) { if (format[paramc] == '|') {
default: /* mark to skip '|' */
if (argc <= i && ! opt) { ext = 1;
pic_errorf(pic, "wrong number of arguments");
}
break;
case '|':
break;
case '*':
break; break;
} }
if (format[paramc] == '*') {
/* in order to run out of all arguments passed to this function rest = true;
(i.e. do va_arg for each argument), optional argument existence
check is done in every case closure */
if (c == '*')
break; break;
}
}
for (optc = 0; rest || format[paramc + optc + ext]; optc++) {
if (format[paramc + optc + ext] == '*') {
rest = true;
break;
}
}
/* '|' should be followed by at least 1 char */
assert(ext <= optc);
/* '*' should not be followed by any char */
assert(format[paramc+optc+ext+rest] == '\0')
/* check argc */
if ((argc < paramc || paramc + optc < argc) && ! rest) {
pic_errorf(pic, "%s: wrong number of arguments (%d for %s%d)",
"procname", argc,
rest? "at least " : "",
paramc);
}
/* start dispatching */
va_start(ap, format);
for(i = 1; i < min(argc, paramc+optc+ext) + 1; i++) {
/* skip '|' if exists. This is always safe because of assert and argc check */
if ( i == paramc)
i += ext;
c = format[i];
switch (c) { switch (c) {
case '|':
opt = true;
break;
case 'o': { case 'o': {
pic_value *p; pic_value *p;
p = va_arg(ap, pic_value*); p = va_arg(ap, pic_value*);
if (i < argc) { *p = GET_OPERAND(pic,i);
*p = GET_OPERAND(pic,i);
i++;
}
break; break;
} }
case 'f': { case 'f': {
double *f; double *f;
f = va_arg(ap, double *); f = va_arg(ap, double *);
if (i < argc) { pic_value v;
pic_value v;
v = GET_OPERAND(pic, i); v = GET_OPERAND(pic, i);
switch (pic_type(v)) { switch (pic_type(v)) {
case PIC_TT_FLOAT: case PIC_TT_FLOAT:
*f = pic_float(v); *f = pic_float(v);
break; break;
case PIC_TT_INT: case PIC_TT_INT:
*f = pic_int(v); *f = pic_int(v);
break; break;
default: default:
pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v); pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -125,23 +139,20 @@ pic_get_args(pic_state *pic, const char *format, ...)
f = va_arg(ap, double *); f = va_arg(ap, double *);
e = va_arg(ap, bool *); e = va_arg(ap, bool *);
if (i < argc) { pic_value v;
pic_value v;
v = GET_OPERAND(pic, i); v = GET_OPERAND(pic, i);
switch (pic_type(v)) { switch (pic_type(v)) {
case PIC_TT_FLOAT: case PIC_TT_FLOAT:
*f = pic_float(v); *f = pic_float(v);
*e = false; *e = false;
break; break;
case PIC_TT_INT: case PIC_TT_INT:
*f = pic_int(v); *f = pic_int(v);
*e = true; *e = true;
break; break;
default: default:
pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v); pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -151,23 +162,20 @@ pic_get_args(pic_state *pic, const char *format, ...)
k = va_arg(ap, int *); k = va_arg(ap, int *);
e = va_arg(ap, bool *); e = va_arg(ap, bool *);
if (i < argc) { pic_value v;
pic_value v;
v = GET_OPERAND(pic, i); v = GET_OPERAND(pic, i);
switch (pic_type(v)) { switch (pic_type(v)) {
case PIC_TT_FLOAT: case PIC_TT_FLOAT:
*k = (int)pic_float(v); *k = (int)pic_float(v);
*e = false; *e = false;
break; break;
case PIC_TT_INT: case PIC_TT_INT:
*k = pic_int(v); *k = pic_int(v);
*e = true; *e = true;
break; break;
default: default:
pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v); pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -175,21 +183,18 @@ pic_get_args(pic_state *pic, const char *format, ...)
int *k; int *k;
k = va_arg(ap, int *); k = va_arg(ap, int *);
if (i < argc) { pic_value v;
pic_value v;
v = GET_OPERAND(pic, i); v = GET_OPERAND(pic, i);
switch (pic_type(v)) { switch (pic_type(v)) {
case PIC_TT_FLOAT: case PIC_TT_FLOAT:
*k = (int)pic_float(v); *k = (int)pic_float(v);
break; break;
case PIC_TT_INT: case PIC_TT_INT:
*k = pic_int(v); *k = pic_int(v);
break; break;
default: default:
pic_errorf(pic, "pic_get_args: expected int, but got ~s", v); pic_errorf(pic, "pic_get_args: expected int, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -197,28 +202,25 @@ pic_get_args(pic_state *pic, const char *format, ...)
size_t *k; size_t *k;
k = va_arg(ap, size_t *); k = va_arg(ap, size_t *);
if (i < argc) { pic_value v;
pic_value v; int x;
int x;
v = GET_OPERAND(pic, i); v = GET_OPERAND(pic, i);
switch (pic_type(v)) { switch (pic_type(v)) {
case PIC_TT_INT: case PIC_TT_INT:
x = pic_int(v); x = pic_int(v);
if (x < 0) { if (x < 0) {
pic_errorf(pic, "pic_get_args: expected non-negative int, but got ~s", v); pic_errorf(pic, "pic_get_args: expected non-negative int, but got ~s", v);
}
if (sizeof(unsigned) > sizeof(size_t)) {
if ((unsigned)x > (unsigned)SIZE_MAX) {
pic_errorf(pic, "pic_get_args: int unrepresentable with size_t ~s", v);
}
}
*k = (size_t)x;
break;
default:
pic_errorf(pic, "pic_get_args: expected int, but got ~s", v);
} }
i++; if (sizeof(unsigned) > sizeof(size_t)) {
if ((unsigned)x > (unsigned)SIZE_MAX) {
pic_errorf(pic, "pic_get_args: int unrepresentable with size_t ~s", v);
}
}
*k = (size_t)x;
break;
default:
pic_errorf(pic, "pic_get_args: expected int, but got ~s", v);
} }
break; break;
} }
@ -227,15 +229,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
str = va_arg(ap, pic_str **); str = va_arg(ap, pic_str **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_str_p(v)) {
if (pic_str_p(v)) { *str = pic_str_ptr(v);
*str = pic_str_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected string, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected string, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -244,14 +243,11 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
cstr = va_arg(ap, const char **); cstr = va_arg(ap, const char **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (! pic_str_p(v)) {
if (! pic_str_p(v)) { pic_errorf(pic, "pic_get_args: expected string, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected string, but got ~s", v);
}
*cstr = pic_str_cstr(pic_str_ptr(v));
i++;
} }
*cstr = pic_str_cstr(pic_str_ptr(v));
break; break;
} }
case 'm': { case 'm': {
@ -259,15 +255,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
m = va_arg(ap, pic_sym **); m = va_arg(ap, pic_sym **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_sym_p(v)) {
if (pic_sym_p(v)) { *m = pic_sym_ptr(v);
*m = pic_sym_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected symbol, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected symbol, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -276,15 +269,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
vec = va_arg(ap, struct pic_vector **); vec = va_arg(ap, struct pic_vector **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_vec_p(v)) {
if (pic_vec_p(v)) { *vec = pic_vec_ptr(v);
*vec = pic_vec_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected vector, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected vector, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -293,15 +283,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
b = va_arg(ap, struct pic_blob **); b = va_arg(ap, struct pic_blob **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_blob_p(v)) {
if (pic_blob_p(v)) { *b = pic_blob_ptr(v);
*b = pic_blob_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected bytevector, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected bytevector, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -310,15 +297,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
k = va_arg(ap, char *); k = va_arg(ap, char *);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_char_p(v)) {
if (pic_char_p(v)) { *k = pic_char(v);
*k = pic_char(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected char, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected char, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -327,15 +311,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
l = va_arg(ap, struct pic_proc **); l = va_arg(ap, struct pic_proc **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_proc_p(v)) {
if (pic_proc_p(v)) { *l = pic_proc_ptr(v);
*l = pic_proc_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args, expected procedure, but got ~s", v);
pic_errorf(pic, "pic_get_args, expected procedure, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -344,15 +325,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
p = va_arg(ap, struct pic_port **); p = va_arg(ap, struct pic_port **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_port_p(v)) {
if (pic_port_p(v)) { *p = pic_port_ptr(v);
*p = pic_port_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args, expected port, but got ~s", v);
pic_errorf(pic, "pic_get_args, expected port, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -361,15 +339,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
d = va_arg(ap, struct pic_dict **); d = va_arg(ap, struct pic_dict **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_dict_p(v)) {
if (pic_dict_p(v)) { *d = pic_dict_ptr(v);
*d = pic_dict_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args, expected dictionary, but got ~s", v);
pic_errorf(pic, "pic_get_args, expected dictionary, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -378,15 +353,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
r = va_arg(ap, struct pic_record **); r = va_arg(ap, struct pic_record **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_record_p(v)) {
if (pic_record_p(v)) { *r = pic_record_ptr(v);
*r = pic_record_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args: expected record, but got ~s", v);
pic_errorf(pic, "pic_get_args: expected record, but got ~s", v);
}
i++;
} }
break; break;
} }
@ -395,15 +367,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_value v; pic_value v;
e = va_arg(ap, struct pic_error **); e = va_arg(ap, struct pic_error **);
if (i < argc) { v = GET_OPERAND(pic,i);
v = GET_OPERAND(pic,i); if (pic_error_p(v)) {
if (pic_error_p(v)) { *e = pic_error_ptr(v);
*e = pic_error_ptr(v); }
} else {
else { pic_errorf(pic, "pic_get_args, expected error");
pic_errorf(pic, "pic_get_args, expected error");
}
i++;
} }
break; break;
} }
@ -411,23 +380,19 @@ pic_get_args(pic_state *pic, const char *format, ...)
pic_errorf(pic, "pic_get_args: invalid argument specifier '%c' given", c); pic_errorf(pic, "pic_get_args: invalid argument specifier '%c' given", c);
} }
} }
if ('*' == c) { if ( rest ) {
size_t *n; size_t *n;
pic_value **argv; pic_value **argv;
n = va_arg(ap, size_t *); n = va_arg(ap, size_t *);
argv = va_arg(ap, pic_value **); argv = va_arg(ap, pic_value **);
if (i <= argc) { if (i <= argc) {
*n = (size_t)(argc - i); *n = (size_t)(argc - (paramc + optc));
*argv = &GET_OPERAND(pic, i); *argv = &GET_OPERAND(pic, i);
i = argc;
} }
} }
else if (argc > i) {
pic_errorf(pic, "wrong number of arguments");
}
va_end(ap); va_end(ap);
return i - 1; return argc - 1;
} }
void void