mirror of
				https://github.com/python/cpython.git
				synced 2025-10-22 17:33:55 +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 %s.\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;
 | |
| }
 | 
