From fe3f1a256bc4f0c359ab843d5de517946916218f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 29 Sep 1994 09:42:55 +0000 Subject: * Python/{modsupport.c,getargs.c,Makefile.in}, Include/modsupport.h: moved getargs() to its own file and re-implemented it entirely to support optional arguments, multiple arguments without surrounding parentheses (when called as newgetargs()), and better error messages --- Python/Makefile.in | 2 +- Python/getargs.c | 587 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Python/modsupport.c | 340 ------------------------------ 3 files changed, 588 insertions(+), 341 deletions(-) create mode 100644 Python/getargs.c diff --git a/Python/Makefile.in b/Python/Makefile.in index ba69a60..ef5b2ef 100644 --- a/Python/Makefile.in +++ b/Python/Makefile.in @@ -34,7 +34,7 @@ OBJS= \ ceval.o cgensupport.o compile.o \ errors.o \ frozenmain.o \ - getmtime.o graminit.o \ + getargs.o getmtime.o graminit.o \ import.o \ marshal.o modsupport.o mystrtoul.o \ pythonmain.o pythonrun.o \ diff --git a/Python/getargs.c b/Python/getargs.c new file mode 100644 index 0000000..605cb01 --- /dev/null +++ b/Python/getargs.c @@ -0,0 +1,587 @@ +/*********************************************************** +Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, +Amsterdam, The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* New getargs implementation */ + +/* XXX There are several unchecked sprintf or strcat calls in this file. + XXX The only way these can become a danger is if some C code in the + XXX Python source (or in an extension) uses ridiculously long names + XXX or riduculously deep nesting in format strings. */ + +#include "allobjects.h" + + +int getargs PROTO((object *, char *, ...)); +int newgetargs PROTO((object *, char *, ...)); +int vgetargs PROTO((object *, char *, va_list)); + + +/* Forward */ +static int vgetargs1 PROTO((object *, char *, va_list, int)); +static void seterror PROTO((int, char *, int *, char *, char *)); +static char *convertitem PROTO((object *, char **, va_list *, int *, char *)); +static char *converttuple PROTO((object *, char **, va_list *, + int *, char *, int)); +static char *convertsimple PROTO((object *, char **, va_list *, char *)); +static char *convertsimple1 PROTO((object *, char **, va_list *)); + + +#ifdef HAVE_STDARG_PROTOTYPES +/* VARARGS2 */ +int getargs(object *args, char *format, ...) +#else +/* VARARGS */ +int getargs(va_alist) va_dcl +#endif +{ + int retval; + va_list va; +#ifdef HAVE_STDARG_PROTOTYPES + + va_start(va, format); +#else + object *args; + char *format; + + va_start(va); + args = va_arg(va, object *); + format = va_arg(va, char *); +#endif + retval = vgetargs1(args, format, va, 1); + va_end(va); + return retval; +} + + +#ifdef HAVE_STDARG_PROTOTYPES +/* VARARGS2 */ +int newgetargs(object *args, char *format, ...) +#else +/* VARARGS */ +int newgetargs(va_alist) va_dcl +#endif +{ + int retval; + va_list va; +#ifdef HAVE_STDARG_PROTOTYPES + + va_start(va, format); +#else + object *args; + char *format; + + va_start(va); + args = va_arg(va, object *); + format = va_arg(va, char *); +#endif + retval = vgetargs1(args, format, va, 0); + va_end(va); + return retval; +} + + +int +vgetargs(args, format, va) + object *args; + char *format; + va_list va; +{ + return vgetargs1(args, format, va, 0); +} + + +static int +vgetargs1(args, format, va, compat) + object *args; + char *format; + va_list va; + int compat; +{ + char msgbuf[256]; + int levels[32]; + char *fname = NULL; + char *message = NULL; + int min = -1; + int max = 0; + int level = 0; + char *formatsave = format; + int i, len; + char *msg; + + for (;;) { + int c = *format++; + if (c == '(' /* ')' */) { + if (level == 0) + max++; + level++; + } + else if (/* '(' */ c == ')') { + if (level == 0) + fatal(/* '(' */ + "excess ')' in getargs format"); + else + level--; + } + else if (c == '\0') + break; + else if (c == ':') { + fname = format; + break; + } + else if (c == ';') { + message = format; + break; + } + else if (level != 0) + ; /* Pass */ + else if (isalpha(c)) + max++; + else if (c == '|') + min = max; + } + + if (level != 0) + fatal(/* '(' */ "missing ')' in getargs format"); + + if (min < 0) + min = max; + + format = formatsave; + + if (compat) { + if (max == 0) { + if (args == NULL) + return 1; + sprintf(msgbuf, "%s requires no arguments", + fname==NULL ? "function" : fname); + err_setstr(TypeError, msgbuf); + return 0; + } + else if (min == 1 && max == 1) { + msg = convertitem(args, &format, &va, levels, msgbuf); + if (msg == NULL) + return 1; + seterror(levels[0], msg, levels+1, fname, message); + return 0; + } + else { + err_setstr(SystemError, + "old style getargs format uses new features"); + return 0; + } + } + + if (!is_tupleobject(args)) { + err_setstr(SystemError, + "new style getargs format but argument is not a tuple"); + return 0; + } + + len = gettuplesize(args); + + if (len < min || max < len) { + if (message == NULL) { + sprintf(msgbuf, + "%s requires %s %d argument%s; %d given", + fname==NULL ? "function" : fname, + min==max ? "exactly" + : len < min ? "at least" : "at most", + len < min ? min : max, + (len < min ? min : max) == 1 ? "" : "s", + len); + message = msgbuf; + } + err_setstr(TypeError, message); + return 0; + } + + for (i = 0; i < len; i++) { + if (*format == '|') + format++; + msg = convertitem(gettupleitem(args, i), &format, &va, + levels, msgbuf); + if (msg) { + seterror(i+1, msg, levels, fname, message); + return 0; + } + } + + return 1; +} + + + +static void +seterror(iarg, msg, levels, fname, message) + int iarg; + char *msg; + int *levels; + char *fname; + char *message; +{ + char buf[256]; + int i; + char *p = buf; + + if (iarg == 0 && message == NULL) + message = msg; + else if (message == NULL) { + if (fname != NULL) { + sprintf(p, "%s, ", fname); + p += strlen(p); + } + sprintf(p, "argument %d", iarg); + i = 0; + p += strlen(p); + while (levels[i] > 0) { + sprintf(p, ", item %d", levels[i]-1); + p += strlen(p); + i++; + } + sprintf(p, ": expected %s found", msg); + message = buf; + } + err_setstr(TypeError, message); +} + + +/* Convert a tuple argument. + On entry, *p_format points to the character _after_ the opening '('. + On successful exit, *p_format points to the closing ')'. + If successful: + *p_format and *p_va are updated, + *levels and *msgbuf are untouched, + and NULL is returned. + If the argument is invalid: + *p_format is unchanged, + *p_va is undefined, + *levels is a 0-terminated list of item numbers, + *msgbuf contains an error message, whose format is: + ", ", where: + is the name of the expected type, and + is the name of the actual type, + (so you can surround it by "expected ... found"), + and msgbuf is returned. +*/ + +static char * +converttuple(arg, p_format, p_va, levels, msgbuf, toplevel) + object *arg; + char **p_format; + va_list *p_va; + int *levels; + char *msgbuf; + int toplevel; +{ + int level = 0; + int n = 0; + char *format = *p_format; + int i; + + for (;;) { + int c = *format++; + if (c == '(') { + if (level == 0) + n++; + level++; + } + else if (c == ')') { + if (level == 0) + break; + level--; + } + else if (c == ':' || c == ';' || c == '\0') + break; + else if (level == 0 && isalpha(c)) + n++; + } + + if (!is_tupleobject(arg)) { + levels[0] = 0; + sprintf(msgbuf, + toplevel ? "%d arguments, %s" : "%d-tuple, %s", + n, arg == None ? "None" : arg->ob_type->tp_name); + return msgbuf; + } + + if ((i = gettuplesize(arg)) != n) { + levels[0] = 0; + sprintf(msgbuf, + toplevel ? "%d arguments, %d" : "%d-tuple, %d-tuple", + n, i); + return msgbuf; + } + + format = *p_format; + for (i = 0; i < n; i++) { + char *msg; + msg = convertitem(gettupleitem(arg, i), &format, p_va, + levels+1, msgbuf); + if (msg != NULL) { + levels[0] = i+1; + return msg; + } + } + + *p_format = format; + return NULL; +} + + +/* Convert a single item. */ + +static char * +convertitem(arg, p_format, p_va, levels, msgbuf) + object *arg; + char **p_format; + va_list *p_va; + int *levels; + char *msgbuf; +{ + char *msg; + char *format = *p_format; + + if (*format == '(' /* ')' */) { + format++; + msg = converttuple(arg, &format, p_va, levels, msgbuf, 0); + if (msg == NULL) + format++; + } + else { + msg = convertsimple(arg, &format, p_va, msgbuf); + if (msg != NULL) + levels[0] = 0; + } + if (msg == NULL) + *p_format = format; + return msg; +} + + +/* Convert a non-tuple argument. Adds to convertsimple1 functionality + by appending ", " to error message. */ + +static char * +convertsimple(arg, p_format, p_va, msgbuf) + object *arg; + char **p_format; + va_list *p_va; + char *msgbuf; +{ + char *msg = convertsimple1(arg, p_format, p_va); + if (msg != NULL) { + sprintf(msgbuf, "%.50s, %.50s", msg, + arg == None ? "None" : arg->ob_type->tp_name); + msg = msgbuf; + } + return msg; +} + + +/* Convert a non-tuple argument. Return NULL if conversion went OK, + or a string representing the expected type if the conversion failed. + When failing, an exception may or may not have been raised. + Don't call if a tuple is expected. */ + +static char * +convertsimple1(arg, p_format, p_va) + object *arg; + char **p_format; + va_list *p_va; +{ + char *format = *p_format; + char c = *format++; + + switch (c) { + + case 'b': /* byte -- very short int */ + { + char *p = va_arg(*p_va, char *); + long ival = getintvalue(arg); + if (ival == -1 && err_occurred()) + return "integer"; + else + *p = ival; + break; + } + + case 'h': /* short int */ + { + short *p = va_arg(*p_va, short *); + long ival = getintvalue(arg); + if (ival == -1 && err_occurred()) + return "integer"; + else + *p = ival; + break; + } + + case 'i': /* int */ + { + int *p = va_arg(*p_va, int *); + long ival = getintvalue(arg); + if (ival == -1 && err_occurred()) + return "integer"; + else + *p = ival; + break; + } + + case 'l': /* long int */ + { + long *p = va_arg(*p_va, long *); + long ival = getintvalue(arg); + if (ival == -1 && err_occurred()) + return "integer"; + else + *p = ival; + break; + } + + case 'f': /* float */ + { + float *p = va_arg(*p_va, float *); + double dval = getfloatvalue(arg); + if (err_occurred()) + return "float"; + else + *p = dval; + break; + } + + case 'd': /* double */ + { + double *p = va_arg(*p_va, double *); + double dval = getfloatvalue(arg); + if (err_occurred()) + return "float"; + else + *p = dval; + break; + } + + case 'c': /* char */ + { + char *p = va_arg(*p_va, char *); + if (is_stringobject(arg) && getstringsize(arg) == 1) + *p = getstringvalue(arg)[0]; + else + return "char"; + break; + } + + case 's': /* string */ + { + char **p = va_arg(*p_va, char **); + if (is_stringobject(arg)) + *p = getstringvalue(arg); + else + return "string"; + if (*format == '#') { + int *q = va_arg(*p_va, int *); + *q = getstringsize(arg); + format++; + } + else if (strlen(*p) != getstringsize(arg)) + return "string without null bytes"; + break; + } + + case 'z': /* string, may be NULL (None) */ + { + char **p = va_arg(*p_va, char **); + if (arg == None) + *p = 0; + else if (is_stringobject(arg)) + *p = getstringvalue(arg); + else + return "None or string"; + if (*format == '#') { + int *q = va_arg(*p_va, int *); + if (arg == None) + *q = 0; + else + *q = getstringsize(arg); + format++; + } + else if (*p != NULL && strlen(*p) != getstringsize(arg)) + return "None or string without null bytes"; + break; + } + + case 'S': /* string object */ + { + object **p = va_arg(*p_va, object **); + if (is_stringobject(arg)) + *p = arg; + else + return "string"; + break; + } + + case 'O': /* object */ + { + typeobject *type; + object **p; + if (*format == '!') { + format++; + type = va_arg(*p_va, typeobject*); + if (arg->ob_type != type) + return type->tp_name; + else { + p = va_arg(*p_va, object **); + *p = arg; + } + } + else if (*format == '?') { + inquiry pred = va_arg(*p_va, inquiry); + format++; + if ((*pred)(arg)) { + p = va_arg(*p_va, object **); + *p = arg; + } + } + else if (*format == '&') { + typedef int (*converter) PROTO((object *, void *)); + converter convert = va_arg(*p_va, converter); + void *addr = va_arg(*p_va, void *); + format++; + if (! (*convert)(arg, addr)) + return ""; + } + else { + p = va_arg(*p_va, object **); + *p = arg; + } + break; + } + + default: + return "impossible"; + + } + + *p_format = format; + return NULL; +} diff --git a/Python/modsupport.c b/Python/modsupport.c index 826e285..ae9a838 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -25,7 +25,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Module support implementation */ #include "allobjects.h" -#include "modsupport.h" #include "import.h" #ifdef MPW /* MPW pushes 'extended' for float and double types with varargs */ @@ -111,345 +110,6 @@ static int countformat(format, endchar) } -/* Generic argument list parser */ - -static int do_arg PROTO((object *arg, char** p_format, va_list *p_va)); -static int -do_arg(arg, p_format, p_va) - object *arg; - char** p_format; - va_list *p_va; -{ - char *format = *p_format; - - if (arg == NULL) - return 0; /* Incomplete tuple or list */ - - switch (*format++) { - - case '(': /* tuple, distributed over C parameters */ { - int i, n; - if (!is_tupleobject(arg)) - return 0; - n = gettuplesize(arg); - for (i = 0; i < n; i++) { - if (!do_arg(gettupleitem(arg, i), &format, p_va)) - return 0; - } - if (*format++ != ')') - return 0; - break; - } - - case ')': /* End of format -- too many arguments */ - return 0; - - case 'b': /* byte -- very short int */ { - char *p = va_arg(*p_va, char *); - long ival = getintvalue(arg); - if (ival == -1 && err_occurred()) - return 0; - else - *p = ival; - break; - } - - case 'h': /* short int */ { - short *p = va_arg(*p_va, short *); - long ival = getintvalue(arg); - if (ival == -1 && err_occurred()) - return 0; - else - *p = ival; - break; - } - - case 'i': /* int */ { - int *p = va_arg(*p_va, int *); - long ival = getintvalue(arg); - if (ival == -1 && err_occurred()) - return 0; - else - *p = ival; - break; - } - - case 'l': /* long int */ { - long *p = va_arg(*p_va, long *); - long ival = getintvalue(arg); - if (ival == -1 && err_occurred()) - return 0; - else - *p = ival; - break; - } - - case 'f': /* float */ { - float *p = va_arg(*p_va, float *); - double dval = getfloatvalue(arg); - if (err_occurred()) - return 0; - else - *p = dval; - break; - } - - case 'd': /* double */ { - double *p = va_arg(*p_va, double *); - double dval = getfloatvalue(arg); - if (err_occurred()) - return 0; - else - *p = dval; - break; - } - - case 'c': /* char */ { - char *p = va_arg(*p_va, char *); - if (is_stringobject(arg) && getstringsize(arg) == 1) - *p = getstringvalue(arg)[0]; - else - return 0; - break; - } - - case 's': /* string */ { - char **p = va_arg(*p_va, char **); - if (is_stringobject(arg)) - *p = getstringvalue(arg); - else - return 0; - if (*format == '#') { - int *q = va_arg(*p_va, int *); - *q = getstringsize(arg); - format++; - } - else if (strlen(*p) != getstringsize(arg)) { - err_setstr(ValueError, "embedded '\\0' in string arg"); - return 0; - } - break; - } - - case 'z': /* string, may be NULL (None) */ { - char **p = va_arg(*p_va, char **); - if (arg == None) - *p = 0; - else if (is_stringobject(arg)) - *p = getstringvalue(arg); - else - return 0; - if (*format == '#') { - int *q = va_arg(*p_va, int *); - if (arg == None) - *q = 0; - else - *q = getstringsize(arg); - format++; - } - else if (*p != NULL && strlen(*p) != getstringsize(arg)) { - err_setstr(ValueError, "embedded '\\0' in string arg"); - return 0; - } - break; - } - - case 'S': /* string object */ { - object **p = va_arg(*p_va, object **); - if (is_stringobject(arg)) - *p = arg; - else - return 0; - break; - } - - case 'O': /* object */ { - typeobject *type; - object **p; - if (*format == '!') { - format++; - type = va_arg(*p_va, typeobject*); - if (arg->ob_type != type) - return 0; - else { - p = va_arg(*p_va, object **); - *p = arg; - } - } - else if (*format == '?') { - inquiry pred = va_arg(*p_va, inquiry); - format++; - if ((*pred)(arg)) { - p = va_arg(*p_va, object **); - *p = arg; - } - } - else if (*format == '&') { - binaryfunc convert = va_arg(*p_va, binaryfunc); - void *addr = va_arg(*p_va, void *); - format++; - if (! (*convert)(arg, addr)) - return 0; - } - else { - p = va_arg(*p_va, object **); - *p = arg; - } - break; - } - - default: - fprintf(stderr, "bad do_arg format: x%x '%c'\n", - format[-1], format[-1]); - return 0; - - } - - *p_format = format; - - return 1; -} - -#ifdef HAVE_STDARG_PROTOTYPES -/* VARARGS2 */ -int getargs(object *arg, char *format, ...) -#else -/* VARARGS */ -int getargs(va_alist) va_dcl -#endif -{ - char *f; - int ok; - va_list va; -#ifdef HAVE_STDARG_PROTOTYPES - - va_start(va, format); -#else - object *arg; - char *format; - - va_start(va); - arg = va_arg(va, object *); - format = va_arg(va, char *); -#endif - if (*format == '\0' || *format == ';') { - va_end(va); - if (arg != NULL) { - char *str = "no arguments needed"; - if (*format == ';') - str = format+1; - err_setstr(TypeError, str); - return 0; - } - return 1; - } - - f = format; - ok = do_arg(arg, &f, &va) && (*f == '\0' || *f == ';'); - va_end(va); - if (!ok) { - if (!err_occurred()) { - char buf[256]; - char *str; - f = strchr(format, ';'); - if (f != NULL) - str = f+1; - else { - sprintf(buf, "bad argument list (format '%s')", - format); - str = buf; - } - err_setstr(TypeError, str); - } - } - return ok; -} - -#ifdef UNUSED - -int -getlongtuplearg(args, a, n) - object *args; - long *a; /* [n] */ - int n; -{ - int i; - if (!is_tupleobject(args) || gettuplesize(args) != n) { - return err_badarg(); - } - for (i = 0; i < n; i++) { - object *v = gettupleitem(args, i); - if (!is_intobject(v)) { - return err_badarg(); - } - a[i] = getintvalue(v); - } - return 1; -} - -int -getshorttuplearg(args, a, n) - object *args; - short *a; /* [n] */ - int n; -{ - int i; - if (!is_tupleobject(args) || gettuplesize(args) != n) { - return err_badarg(); - } - for (i = 0; i < n; i++) { - object *v = gettupleitem(args, i); - if (!is_intobject(v)) { - return err_badarg(); - } - a[i] = getintvalue(v); - } - return 1; -} - -int -getlonglistarg(args, a, n) - object *args; - long *a; /* [n] */ - int n; -{ - int i; - if (!is_listobject(args) || getlistsize(args) != n) { - return err_badarg(); - } - for (i = 0; i < n; i++) { - object *v = getlistitem(args, i); - if (!is_intobject(v)) { - return err_badarg(); - } - a[i] = getintvalue(v); - } - return 1; -} - -int -getshortlistarg(args, a, n) - object *args; - short *a; /* [n] */ - int n; -{ - int i; - if (!is_listobject(args) || getlistsize(args) != n) { - return err_badarg(); - } - for (i = 0; i < n; i++) { - object *v = getlistitem(args, i); - if (!is_intobject(v)) { - return err_badarg(); - } - a[i] = getintvalue(v); - } - return 1; -} - -#endif /* UNUSED */ - - /* Generic function to create a value -- the inverse of getargs() */ /* After an original idea and first implementation by Steven Miale */ -- cgit v0.12