rewrite to be clean

This commit is contained in:
Sunrin SHIMURA (keen) 2015-02-03 16:57:39 +00:00
parent 9571030f7e
commit 1700610729
1 changed files with 36 additions and 31 deletions

View File

@ -58,38 +58,43 @@ int
pic_get_args(pic_state *pic, const char *format, ...) pic_get_args(pic_state *pic, const char *format, ...)
{ {
char c; char c;
int paramc, optc, ext = 0; int paramc, optc, min;
int i , argc = pic->ci->argc; int i , argc = pic->ci->argc - 1;
va_list ap; va_list ap;
bool rest = false; bool rest = false, opt = false;
/* paramc: required args count as scheme proc
optc: optional args count as scheme proc
argc: passed args count as scheme proc
vargc: args count passed to this function
*/
/* check nparams first */ /* check nparams first */
for (paramc = 0; format[paramc]; paramc++) { for (paramc = 0, c = *format; c; c = format[++paramc]) {
if (format[paramc] == '|') { if (c == '|') {
/* mark to skip '|' */ opt = true;
ext = 1;
break; break;
} }
if (format[paramc] == '*') { else if (c == '*') {
rest = true; rest = true;
break; break;
} }
} }
for (optc = 0; rest || format[paramc + optc + ext]; optc++) { for (optc = 0; opt && c; c = format[paramc + opt + ++optc]) {
if (format[paramc + optc + ext] == '*') { if (c == '*') {
rest = true; rest = true;
break; break;
} }
} }
/* '|' should be followed by at least 1 char */ /* '|' should be followed by at least 1 char */
assert(ext <= optc); assert(opt <= optc);
/* '*' should not be followed by any char */ /* '*' should not be followed by any char */
assert(format[paramc+optc+ext+rest] == '\0') assert(format[paramc + opt + optc + rest] == '\0');
/* check argc */ /* check argc. */
if ((argc < paramc || paramc + optc < argc) && ! rest) { if (argc < paramc || (paramc + optc < argc && ! rest)) {
pic_errorf(pic, "%s: wrong number of arguments (%d for %s%d)", pic_errorf(pic, "%s: wrong number of arguments (%d for %s%d)",
"procname", argc, "procname", argc,
rest? "at least " : "", rest? "at least " : "",
@ -98,13 +103,12 @@ pic_get_args(pic_state *pic, const char *format, ...)
/* start dispatching */ /* start dispatching */
va_start(ap, format); va_start(ap, format);
for(i = 1; i < min(argc, paramc+optc+ext) + 1; i++) { min = paramc + optc + rest < argc ? paramc + optc + rest : argc;
for(i = 1; i < min + 1; i++) {
c = *format++;
/* skip '|' if exists. This is always safe because of assert and argc check */ /* skip '|' if exists. This is always safe because of assert and argc check */
if ( i == paramc) c = c == '|' ? *format++ : c;
i += ext;
c = format[i];
switch (c) { switch (c) {
case 'o': { case 'o': {
@ -378,23 +382,24 @@ pic_get_args(pic_state *pic, const char *format, ...)
} }
break; break;
} }
case '*': {
size_t *n;
pic_value **argv;
n = va_arg(ap, size_t *);
argv = va_arg(ap, pic_value **);
if ( paramc + optc < argc) {
*n = (size_t)(argc - (paramc + optc));
*argv = &GET_OPERAND(pic, i);
}
break;
}
default: default:
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 ( rest ) {
size_t *n;
pic_value **argv;
n = va_arg(ap, size_t *);
argv = va_arg(ap, pic_value **);
if (i <= argc) {
*n = (size_t)(argc - (paramc + optc));
*argv = &GET_OPERAND(pic, i);
}
}
va_end(ap); va_end(ap);
return argc - 1; return argc;
} }
void void