mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			487 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			487 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.
 | 
						|
 | 
						|
******************************************************************/
 | 
						|
 | 
						|
/* struct module -- pack values into and (out of) strings */
 | 
						|
 | 
						|
#include "allobjects.h"
 | 
						|
#include "modsupport.h"
 | 
						|
 | 
						|
static object *StructError;
 | 
						|
 | 
						|
 | 
						|
/* Define various structs to figure out the alignments of types */
 | 
						|
 | 
						|
#ifdef __MWERKS__
 | 
						|
/*
 | 
						|
** XXXX We have a problem here. There are no unique alignment rules
 | 
						|
** on the PowerPC mac. 
 | 
						|
*/
 | 
						|
#ifdef __powerc
 | 
						|
#pragma options align=mac68k
 | 
						|
#endif
 | 
						|
#endif /* __MWERKS__ */
 | 
						|
 | 
						|
typedef struct { char c; short x; } s_short;
 | 
						|
typedef struct { char c; int x; } s_int;
 | 
						|
typedef struct { char c; long x; } s_long;
 | 
						|
typedef struct { char c; float x; } s_float;
 | 
						|
typedef struct { char c; double x; } s_double;
 | 
						|
 | 
						|
#define SHORT_ALIGN (sizeof(s_short) - sizeof(short))
 | 
						|
#define INT_ALIGN (sizeof(s_int) - sizeof(int))
 | 
						|
#define LONG_ALIGN (sizeof(s_long) - sizeof(long))
 | 
						|
#define FLOAT_ALIGN (sizeof(s_float) - sizeof(float))
 | 
						|
#define DOUBLE_ALIGN (sizeof(s_double) - sizeof(double))
 | 
						|
 | 
						|
#ifdef __powerc
 | 
						|
#pragma options align=reset
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* Align a size according to a format code */
 | 
						|
 | 
						|
static int
 | 
						|
align(size, c)
 | 
						|
	int size;
 | 
						|
	int c;
 | 
						|
{
 | 
						|
	int a;
 | 
						|
 | 
						|
	switch (c) {
 | 
						|
	case 'h': a = SHORT_ALIGN; break;
 | 
						|
	case 'i': a = INT_ALIGN; break;
 | 
						|
	case 'l': a = LONG_ALIGN; break;
 | 
						|
	case 'f': a = FLOAT_ALIGN; break;
 | 
						|
	case 'd': a = DOUBLE_ALIGN; break;
 | 
						|
	default: return size;
 | 
						|
	}
 | 
						|
	return (size + a - 1) / a * a;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* calculate the size of a format string */
 | 
						|
 | 
						|
static int
 | 
						|
calcsize(fmt)
 | 
						|
	char *fmt;
 | 
						|
{
 | 
						|
	char *s;
 | 
						|
	char c;
 | 
						|
	int size,  num, itemsize, x;
 | 
						|
 | 
						|
	s = fmt;
 | 
						|
	size = 0;
 | 
						|
	while ((c = *s++) != '\0') {
 | 
						|
		if ('0' <= c && c <= '9') {
 | 
						|
			num = c - '0';
 | 
						|
			while ('0' <= (c = *s++) && c <= '9') {
 | 
						|
				x = num*10 + (c - '0');
 | 
						|
				if (x/10 != num) {
 | 
						|
					err_setstr(StructError,
 | 
						|
						   "int overflow in fmt");
 | 
						|
					return -1;
 | 
						|
				}
 | 
						|
				num = x;
 | 
						|
			}
 | 
						|
			if (c == '\0')
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			num = 1;
 | 
						|
		
 | 
						|
		size = align(size, c);
 | 
						|
		
 | 
						|
		switch (c) {
 | 
						|
			
 | 
						|
		case 'x': /* pad byte */
 | 
						|
		case 'b': /* byte-sized int */
 | 
						|
		case 'c': /* char */
 | 
						|
			itemsize = 1;
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'h': /* short ("half-size)" int */
 | 
						|
			itemsize = sizeof(short);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'i': /* natural-size int */
 | 
						|
			itemsize = sizeof(int);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'l': /* long int */
 | 
						|
			itemsize = sizeof(long);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'f': /* float */
 | 
						|
			itemsize = sizeof(float);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 'd': /* double */
 | 
						|
			itemsize = sizeof(double);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			err_setstr(StructError, "bad char in fmt");
 | 
						|
			return -1;
 | 
						|
 | 
						|
		}
 | 
						|
		
 | 
						|
		x = num * itemsize;
 | 
						|
		size += x;
 | 
						|
		if (x/itemsize != num || size < 0) {
 | 
						|
			err_setstr(StructError, "total struct size too long");
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
			
 | 
						|
	}
 | 
						|
 | 
						|
	return size;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* pack(fmt, v1, v2, ...) --> string */
 | 
						|
 | 
						|
static object *
 | 
						|
struct_calcsize(self, args)
 | 
						|
	object *self; /* Not used */
 | 
						|
	object *args;
 | 
						|
{
 | 
						|
	char *fmt;
 | 
						|
	int size;
 | 
						|
 | 
						|
	if (!getargs(args, "s", &fmt))
 | 
						|
		return NULL;
 | 
						|
	size = calcsize(fmt);
 | 
						|
	if (size < 0)
 | 
						|
		return NULL;
 | 
						|
	return newintobject((long)size);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* pack(fmt, v1, v2, ...) --> string */
 | 
						|
 | 
						|
static object *
 | 
						|
struct_pack(self, args)
 | 
						|
	object *self; /* Not used */
 | 
						|
	object *args;
 | 
						|
{
 | 
						|
	object *format, *result, *v;
 | 
						|
	char *fmt;
 | 
						|
	int size, num;
 | 
						|
	int i, n;
 | 
						|
	char *s, *res, *restart;
 | 
						|
	char c;
 | 
						|
	long ival;
 | 
						|
	double fval;
 | 
						|
 | 
						|
	if (args == NULL || !is_tupleobject(args) ||
 | 
						|
	    (n = gettuplesize(args)) < 1) {
 | 
						|
		err_badarg();
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	format = gettupleitem(args, 0);
 | 
						|
	if (!getargs(format, "s", &fmt))
 | 
						|
		return NULL;
 | 
						|
	size = calcsize(fmt);
 | 
						|
	if (size < 0)
 | 
						|
		return NULL;
 | 
						|
	result = newsizedstringobject((char *)NULL, size);
 | 
						|
	if (result == NULL)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	s = fmt;
 | 
						|
	i = 1;
 | 
						|
	res = restart = getstringvalue(result);
 | 
						|
 | 
						|
	while ((c = *s++) != '\0') {
 | 
						|
		if ('0' <= c && c <= '9') {
 | 
						|
			num = c - '0';
 | 
						|
			while ('0' <= (c = *s++) && c <= '9')
 | 
						|
			       num = num*10 + (c - '0');
 | 
						|
			if (c == '\0')
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			num = 1;
 | 
						|
 | 
						|
		res = restart + align((int)(res-restart), c);
 | 
						|
 | 
						|
		while (--num >= 0) {
 | 
						|
			switch (c) {
 | 
						|
 | 
						|
			case 'x': /* pad byte */
 | 
						|
				*res++ = '\0';
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'l':
 | 
						|
			case 'i':
 | 
						|
			case 'h':
 | 
						|
			case 'b':
 | 
						|
				if (i >= n) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "insufficient arguments to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				v = gettupleitem(args, i++);
 | 
						|
				if (!is_intobject(v)) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "bad argument type to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				ival = getintvalue(v);
 | 
						|
				switch (c) {
 | 
						|
				case 'b':
 | 
						|
					*res++ = ival;
 | 
						|
					break;
 | 
						|
				case 'h':
 | 
						|
					*(short*)res = ival;
 | 
						|
					res += sizeof(short);
 | 
						|
					break;
 | 
						|
				case 'i':
 | 
						|
					*(int*)res = ival;
 | 
						|
					res += sizeof(int);
 | 
						|
					break;
 | 
						|
				case 'l':
 | 
						|
					*(long*)res = ival;
 | 
						|
					res += sizeof(long);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'c':
 | 
						|
				if (i >= n) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "insufficient arguments to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				v = gettupleitem(args, i++);
 | 
						|
				if (!is_stringobject(v) ||
 | 
						|
				    getstringsize(v) != 1) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "bad argument type to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				*res++ = getstringvalue(v)[0];
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'd':
 | 
						|
			case 'f':
 | 
						|
				if (i >= n) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "insufficient arguments to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				v = gettupleitem(args, i++);
 | 
						|
				if (!is_floatobject(v)) {
 | 
						|
					err_setstr(StructError,
 | 
						|
					   "bad argument type to pack");
 | 
						|
					goto fail;
 | 
						|
				}
 | 
						|
				fval = getfloatvalue(v);
 | 
						|
				switch (c) {
 | 
						|
				case 'f':
 | 
						|
					*(float*)res = (float)fval;
 | 
						|
					res += sizeof(float);
 | 
						|
					break;
 | 
						|
				case 'd':
 | 
						|
					memcpy(res, (char*)&fval, sizeof fval);
 | 
						|
					res += sizeof(double);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				err_setstr(StructError, "bad char in fmt");
 | 
						|
				goto fail;
 | 
						|
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (i < n) {
 | 
						|
		err_setstr(StructError, "too many arguments for pack fmt");
 | 
						|
		goto fail;
 | 
						|
	}
 | 
						|
 | 
						|
	return result;
 | 
						|
 | 
						|
 fail:
 | 
						|
	DECREF(result);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Helper to convert a list to a tuple */
 | 
						|
 | 
						|
static object *
 | 
						|
totuple(list)
 | 
						|
	object *list;
 | 
						|
{
 | 
						|
	int len = getlistsize(list);
 | 
						|
	object *tuple = newtupleobject(len);
 | 
						|
	if (tuple != NULL) {
 | 
						|
		int i;
 | 
						|
		for (i = 0; i < len; i++) {
 | 
						|
			object *v = getlistitem(list, i);
 | 
						|
			INCREF(v);
 | 
						|
			settupleitem(tuple, i, v);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	DECREF(list);
 | 
						|
	return tuple;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* unpack(fmt, string) --> (v1, v2, ...) */
 | 
						|
 | 
						|
static object *
 | 
						|
struct_unpack(self, args)
 | 
						|
	object *self; /* Not used */
 | 
						|
	object *args;
 | 
						|
{
 | 
						|
	char *str, *start, *fmt, *s;
 | 
						|
	char c;
 | 
						|
	int len, size, num, x;
 | 
						|
	object *res, *v;
 | 
						|
 | 
						|
	if (!getargs(args, "(ss#)", &fmt, &start, &len))
 | 
						|
		return NULL;
 | 
						|
	size = calcsize(fmt);
 | 
						|
	if (size != len) {
 | 
						|
		err_setstr(StructError, "unpack str size does not match fmt");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	res = newlistobject(0);
 | 
						|
	if (res == NULL)
 | 
						|
		return NULL;
 | 
						|
	str = start;
 | 
						|
	s = fmt;
 | 
						|
	while ((c = *s++) != '\0') {
 | 
						|
		if ('0' <= c && c <= '9') {
 | 
						|
			num = c - '0';
 | 
						|
			while ('0' <= (c = *s++) && c <= '9')
 | 
						|
			       num = num*10 + (c - '0');
 | 
						|
			if (c == '\0')
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			num = 1;
 | 
						|
 | 
						|
		str = start + align((int)(str-start), c);
 | 
						|
 | 
						|
		while (--num >= 0) {
 | 
						|
			switch (c) {
 | 
						|
 | 
						|
			case 'x':
 | 
						|
				str++;
 | 
						|
				continue;
 | 
						|
 | 
						|
			case 'b':
 | 
						|
				x = *str++;
 | 
						|
				if (x >= 128)
 | 
						|
					x -= 256;
 | 
						|
				v = newintobject((long)x);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'c':
 | 
						|
				v = newsizedstringobject(str, 1);
 | 
						|
				str++;
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'h':
 | 
						|
				v = newintobject((long)*(short*)str);
 | 
						|
				str += sizeof(short);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'i':
 | 
						|
				v = newintobject((long)*(int*)str);
 | 
						|
				str += sizeof(int);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'l':
 | 
						|
				v = newintobject(*(long*)str);
 | 
						|
				str += sizeof(long);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'f':
 | 
						|
				v = newfloatobject((double)*(float*)str);
 | 
						|
				str += sizeof(float);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'd':
 | 
						|
			    {
 | 
						|
				double d;
 | 
						|
				memcpy((char *)&d, str, sizeof d);
 | 
						|
				v = newfloatobject(d);
 | 
						|
				str += sizeof(double);
 | 
						|
				break;
 | 
						|
			    }
 | 
						|
 | 
						|
			default:
 | 
						|
				err_setstr(StructError, "bad char in fmt");
 | 
						|
				goto fail;
 | 
						|
 | 
						|
			}
 | 
						|
			if (v == NULL || addlistitem(res, v) < 0)
 | 
						|
				goto fail;
 | 
						|
			DECREF(v);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return totuple(res);
 | 
						|
 | 
						|
 fail:
 | 
						|
	DECREF(res);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* List of functions */
 | 
						|
 | 
						|
static struct methodlist struct_methods[] = {
 | 
						|
	{"calcsize",	struct_calcsize},
 | 
						|
	{"pack",	struct_pack,	1/*varargs*/},
 | 
						|
	{"unpack",	struct_unpack},
 | 
						|
	{NULL,		NULL}		/* sentinel */
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/* Module initialization */
 | 
						|
 | 
						|
void
 | 
						|
initstruct()
 | 
						|
{
 | 
						|
	object *m, *d;
 | 
						|
 | 
						|
	/* Create the module and add the functions */
 | 
						|
	m = initmodule("struct", struct_methods);
 | 
						|
 | 
						|
	/* Add some symbolic constants to the module */
 | 
						|
	d = getmoduledict(m);
 | 
						|
	StructError = newstringobject("struct.error");
 | 
						|
	dictinsert(d, "error", StructError);
 | 
						|
 | 
						|
	/* Check for errors */
 | 
						|
	if (err_occurred())
 | 
						|
		fatal("can't initialize module struct");
 | 
						|
}
 |