mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			472 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			472 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/***********************************************************
 | 
						|
Copyright 1991-1995 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.
 | 
						|
 | 
						|
******************************************************************/
 | 
						|
 | 
						|
/* Module support implementation */
 | 
						|
 | 
						|
#include "allobjects.h"
 | 
						|
#include "import.h"
 | 
						|
 | 
						|
#ifdef MPW /* MPW pushes 'extended' for float and double types with varargs */
 | 
						|
typedef extended va_double;
 | 
						|
#else
 | 
						|
typedef double va_double;
 | 
						|
#endif
 | 
						|
 | 
						|
/* initmodule4() parameters:
 | 
						|
   - name is the module name
 | 
						|
   - methods is the list of top-level functions
 | 
						|
   - doc is the documentation string
 | 
						|
   - passthrough is passed as self to functions defined in the module
 | 
						|
   - api_version is the value of PYTHON_API_VERSION at the time the
 | 
						|
     module was compiled
 | 
						|
*/
 | 
						|
 | 
						|
static char api_version_warning[] =
 | 
						|
"WARNING: Python C API version mismatch for module %s:\n\
 | 
						|
  This Python has API version %d, module %s has version %d.\n";
 | 
						|
 | 
						|
object *
 | 
						|
initmodule4(name, methods, doc, passthrough, module_api_version)
 | 
						|
	char *name;
 | 
						|
	struct methodlist *methods;
 | 
						|
	char *doc;
 | 
						|
	object *passthrough;
 | 
						|
	int module_api_version;
 | 
						|
{
 | 
						|
	object *m, *d, *v;
 | 
						|
	struct methodlist *ml;
 | 
						|
	if (module_api_version != PYTHON_API_VERSION)
 | 
						|
		fprintf(stderr, api_version_warning,
 | 
						|
			name, PYTHON_API_VERSION, name, module_api_version);
 | 
						|
	if ((m = add_module(name)) == NULL) {
 | 
						|
		fprintf(stderr, "initializing module: %s\n", name);
 | 
						|
		fatal("can't create a module");
 | 
						|
	}
 | 
						|
	d = getmoduledict(m);
 | 
						|
	for (ml = methods; ml->ml_name != NULL; ml++) {
 | 
						|
		v = newmethodobject(ml, passthrough);
 | 
						|
		if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) {
 | 
						|
			fprintf(stderr, "initializing module: %s\n", name);
 | 
						|
			fatal("can't initialize module");
 | 
						|
		}
 | 
						|
		DECREF(v);
 | 
						|
	}
 | 
						|
	if (doc != NULL) {
 | 
						|
		v = newstringobject(doc);
 | 
						|
		if (v == NULL || dictinsert(d, "__doc__", v) != 0)
 | 
						|
			fatal("can't add doc string");
 | 
						|
		DECREF(v);
 | 
						|
	}
 | 
						|
	return m;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Helper for mkvalue() to scan the length of a format */
 | 
						|
 | 
						|
static int countformat PROTO((char *format, int endchar));
 | 
						|
static int countformat(format, endchar)
 | 
						|
	char *format;
 | 
						|
	int endchar;
 | 
						|
{
 | 
						|
	int count = 0;
 | 
						|
	int level = 0;
 | 
						|
	while (level > 0 || *format != endchar) {
 | 
						|
		switch (*format) {
 | 
						|
		case '\0':
 | 
						|
			/* Premature end */
 | 
						|
			err_setstr(SystemError, "unmatched paren in format");
 | 
						|
			return -1;
 | 
						|
		case '(':
 | 
						|
		case '[':
 | 
						|
		case '{':
 | 
						|
			if (level == 0)
 | 
						|
				count++;
 | 
						|
			level++;
 | 
						|
			break;
 | 
						|
		case ')':
 | 
						|
		case ']':
 | 
						|
		case '}':
 | 
						|
			level--;
 | 
						|
			break;
 | 
						|
		case '#':
 | 
						|
		case '&':
 | 
						|
		case ',':
 | 
						|
		case ':':
 | 
						|
		case ' ':
 | 
						|
		case '\t':
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			if (level == 0)
 | 
						|
				count++;
 | 
						|
		}
 | 
						|
		format++;
 | 
						|
	}
 | 
						|
	return count;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Generic function to create a value -- the inverse of getargs() */
 | 
						|
/* After an original idea and first implementation by Steven Miale */
 | 
						|
 | 
						|
static object *do_mktuple PROTO((char**, va_list *, int, int));
 | 
						|
static object *do_mklist PROTO((char**, va_list *, int, int));
 | 
						|
static object *do_mkdict PROTO((char**, va_list *, int, int));
 | 
						|
static object *do_mkvalue PROTO((char**, va_list *));
 | 
						|
 | 
						|
 | 
						|
static object *
 | 
						|
do_mkdict(p_format, p_va, endchar, n)
 | 
						|
	char **p_format;
 | 
						|
	va_list *p_va;
 | 
						|
	int endchar;
 | 
						|
	int n;
 | 
						|
{
 | 
						|
	object *d;
 | 
						|
	int i;
 | 
						|
	if (n < 0)
 | 
						|
		return NULL;
 | 
						|
	if ((d = newdictobject()) == NULL)
 | 
						|
		return NULL;
 | 
						|
	for (i = 0; i < n; i+= 2) {
 | 
						|
		object *k, *v;
 | 
						|
		k = do_mkvalue(p_format, p_va);
 | 
						|
		if (k == NULL) {
 | 
						|
			DECREF(d);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		v = do_mkvalue(p_format, p_va);
 | 
						|
		if (v == NULL) {
 | 
						|
			DECREF(k);
 | 
						|
			DECREF(d);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		if (dict2insert(d, k, v) < 0) {
 | 
						|
			DECREF(k);
 | 
						|
			DECREF(v);
 | 
						|
			DECREF(d);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (d != NULL && **p_format != endchar) {
 | 
						|
		DECREF(d);
 | 
						|
		d = NULL;
 | 
						|
		err_setstr(SystemError, "Unmatched paren in format");
 | 
						|
	}
 | 
						|
	else if (endchar)
 | 
						|
		++*p_format;
 | 
						|
	return d;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
do_mklist(p_format, p_va, endchar, n)
 | 
						|
	char **p_format;
 | 
						|
	va_list *p_va;
 | 
						|
	int endchar;
 | 
						|
	int n;
 | 
						|
{
 | 
						|
	object *v;
 | 
						|
	int i;
 | 
						|
	if (n < 0)
 | 
						|
		return NULL;
 | 
						|
	if ((v = newlistobject(n)) == NULL)
 | 
						|
		return NULL;
 | 
						|
	for (i = 0; i < n; i++) {
 | 
						|
		object *w = do_mkvalue(p_format, p_va);
 | 
						|
		if (w == NULL) {
 | 
						|
			DECREF(v);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		setlistitem(v, i, w);
 | 
						|
	}
 | 
						|
	if (v != NULL && **p_format != endchar) {
 | 
						|
		DECREF(v);
 | 
						|
		v = NULL;
 | 
						|
		err_setstr(SystemError, "Unmatched paren in format");
 | 
						|
	}
 | 
						|
	else if (endchar)
 | 
						|
		++*p_format;
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
do_mktuple(p_format, p_va, endchar, n)
 | 
						|
	char **p_format;
 | 
						|
	va_list *p_va;
 | 
						|
	int endchar;
 | 
						|
	int n;
 | 
						|
{
 | 
						|
	object *v;
 | 
						|
	int i;
 | 
						|
	if (n < 0)
 | 
						|
		return NULL;
 | 
						|
	if ((v = newtupleobject(n)) == NULL)
 | 
						|
		return NULL;
 | 
						|
	for (i = 0; i < n; i++) {
 | 
						|
		object *w = do_mkvalue(p_format, p_va);
 | 
						|
		if (w == NULL) {
 | 
						|
			DECREF(v);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		settupleitem(v, i, w);
 | 
						|
	}
 | 
						|
	if (v != NULL && **p_format != endchar) {
 | 
						|
		DECREF(v);
 | 
						|
		v = NULL;
 | 
						|
		err_setstr(SystemError, "Unmatched paren in format");
 | 
						|
	}
 | 
						|
	else if (endchar)
 | 
						|
		++*p_format;
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
do_mkvalue(p_format, p_va)
 | 
						|
	char **p_format;
 | 
						|
	va_list *p_va;
 | 
						|
{
 | 
						|
	for (;;) {
 | 
						|
		switch (*(*p_format)++) {
 | 
						|
		case '(':
 | 
						|
			return do_mktuple(p_format, p_va, ')',
 | 
						|
					  countformat(*p_format, ')'));
 | 
						|
 | 
						|
		case '[':
 | 
						|
			return do_mklist(p_format, p_va, ']',
 | 
						|
					 countformat(*p_format, ']'));
 | 
						|
 | 
						|
		case '{':
 | 
						|
			return do_mkdict(p_format, p_va, '}',
 | 
						|
					 countformat(*p_format, '}'));
 | 
						|
 | 
						|
		case 'b':
 | 
						|
		case 'h':
 | 
						|
		case 'i':
 | 
						|
			return newintobject((long)va_arg(*p_va, int));
 | 
						|
 | 
						|
		case 'l':
 | 
						|
			return newintobject((long)va_arg(*p_va, long));
 | 
						|
 | 
						|
		case 'f':
 | 
						|
		case 'd':
 | 
						|
			return newfloatobject((double)va_arg(*p_va, va_double));
 | 
						|
 | 
						|
		case 'c':
 | 
						|
		{
 | 
						|
			char p[1];
 | 
						|
			p[0] = va_arg(*p_va, int);
 | 
						|
			return newsizedstringobject(p, 1);
 | 
						|
		}
 | 
						|
 | 
						|
		case 's':
 | 
						|
		case 'z':
 | 
						|
		{
 | 
						|
			object *v;
 | 
						|
			char *str = va_arg(*p_va, char *);
 | 
						|
			int n;
 | 
						|
			if (**p_format == '#') {
 | 
						|
				++*p_format;
 | 
						|
				n = va_arg(*p_va, int);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				n = -1;
 | 
						|
			if (str == NULL) {
 | 
						|
				v = None;
 | 
						|
				INCREF(v);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (n < 0)
 | 
						|
					n = strlen(str);
 | 
						|
				v = newsizedstringobject(str, n);
 | 
						|
			}
 | 
						|
			return v;
 | 
						|
		}
 | 
						|
 | 
						|
		case 'S':
 | 
						|
		case 'O':
 | 
						|
		if (**p_format == '&') {
 | 
						|
			typedef object *(*converter) PROTO((void *));
 | 
						|
			converter func = va_arg(*p_va, converter);
 | 
						|
			void *arg = va_arg(*p_va, void *);
 | 
						|
			++*p_format;
 | 
						|
			return (*func)(arg);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			object *v;
 | 
						|
			v = va_arg(*p_va, object *);
 | 
						|
			if (v != NULL)
 | 
						|
				INCREF(v);
 | 
						|
			else if (!err_occurred())
 | 
						|
				/* If a NULL was passed
 | 
						|
				 * because a call that should
 | 
						|
				 * have constructed a value
 | 
						|
				 * failed, that's OK, and we
 | 
						|
				 * pass the error on; but if
 | 
						|
				 * no error occurred it's not
 | 
						|
				 * clear that the caller knew
 | 
						|
				 * what she was doing. */
 | 
						|
				err_setstr(SystemError,
 | 
						|
					   "NULL object passed to mkvalue");
 | 
						|
			return v;
 | 
						|
		}
 | 
						|
 | 
						|
		case ':':
 | 
						|
		case ',':
 | 
						|
		case ' ':
 | 
						|
		case '\t':
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			err_setstr(SystemError,
 | 
						|
				   "bad format char passed to mkvalue");
 | 
						|
			return NULL;
 | 
						|
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
/* VARARGS 2 */
 | 
						|
object *mkvalue(char *format, ...)
 | 
						|
#else
 | 
						|
/* VARARGS */
 | 
						|
object *mkvalue(va_alist) va_dcl
 | 
						|
#endif
 | 
						|
{
 | 
						|
	va_list va;
 | 
						|
	object* retval;
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
	va_start(va, format);
 | 
						|
#else
 | 
						|
	char *format;
 | 
						|
	va_start(va);
 | 
						|
	format = va_arg(va, char *);
 | 
						|
#endif
 | 
						|
	retval = vmkvalue(format, va);
 | 
						|
	va_end(va);
 | 
						|
	return retval;
 | 
						|
}
 | 
						|
 | 
						|
object *
 | 
						|
vmkvalue(format, va)
 | 
						|
	char *format;
 | 
						|
	va_list va;
 | 
						|
{
 | 
						|
	char *f = format;
 | 
						|
	int n = countformat(f, '\0');
 | 
						|
	va_list lva;
 | 
						|
 | 
						|
#ifdef VA_LIST_IS_ARRAY
 | 
						|
	memcpy(lva, va, sizeof(va_list));
 | 
						|
#else
 | 
						|
	lva = va;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (n < 0)
 | 
						|
		return NULL;
 | 
						|
	if (n == 0) {
 | 
						|
		INCREF(None);
 | 
						|
		return None;
 | 
						|
	}
 | 
						|
	if (n == 1)
 | 
						|
		return do_mkvalue(&f, &lva);
 | 
						|
	return do_mktuple(&f, &lva, '\0', n);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
object *
 | 
						|
PyEval_CallFunction(object *obj, char *format, ...)
 | 
						|
#else
 | 
						|
object *
 | 
						|
PyEval_CallFunction(obj, format, va_alist)
 | 
						|
	object *obj;
 | 
						|
	char *format;
 | 
						|
	va_dcl
 | 
						|
#endif
 | 
						|
{
 | 
						|
	va_list vargs;
 | 
						|
	object *args;
 | 
						|
	object *res;
 | 
						|
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
	va_start(vargs, format);
 | 
						|
#else
 | 
						|
	va_start(vargs);
 | 
						|
#endif
 | 
						|
 | 
						|
	args = vmkvalue(format, vargs);
 | 
						|
	va_end(vargs);
 | 
						|
 | 
						|
	if (args == NULL)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	res = call_object(obj, args);
 | 
						|
	DECREF(args);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
object *
 | 
						|
PyEval_CallMethod(object *obj, char *methonname, char *format, ...)
 | 
						|
#else
 | 
						|
object *
 | 
						|
PyEval_CallMethod(obj, methonname, format, va_alist)
 | 
						|
	object *obj;
 | 
						|
	char *methonname;
 | 
						|
	char *format;
 | 
						|
	va_dcl
 | 
						|
#endif
 | 
						|
{
 | 
						|
	va_list vargs;
 | 
						|
	object *meth;
 | 
						|
	object *args;
 | 
						|
	object *res;
 | 
						|
 | 
						|
	meth = getattr(obj, methonname);
 | 
						|
	if (meth == NULL)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
#ifdef HAVE_STDARG_PROTOTYPES
 | 
						|
	va_start(vargs, format);
 | 
						|
#else
 | 
						|
	va_start(vargs);
 | 
						|
#endif
 | 
						|
 | 
						|
	args = vmkvalue(format, vargs);
 | 
						|
	va_end(vargs);
 | 
						|
 | 
						|
	if (args == NULL) {
 | 
						|
		DECREF(meth);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	res = call_object(meth, args);
 | 
						|
	DECREF(meth);
 | 
						|
	DECREF(args);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 |