diff options
author | Guido van Rossum <guido@python.org> | 1992-08-17 08:55:12 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1992-08-17 08:55:12 (GMT) |
commit | 0297512a08698cdee4bebe044a40b08b406398a8 (patch) | |
tree | 52ceb535f0f2b4068f1a5ce1f17c199477437b67 /Modules/structmodule.c | |
parent | 94390a4eaf48c3ddf91cdbf78fcf5db7b57972ec (diff) | |
download | cpython-0297512a08698cdee4bebe044a40b08b406398a8.zip cpython-0297512a08698cdee4bebe044a40b08b406398a8.tar.gz cpython-0297512a08698cdee4bebe044a40b08b406398a8.tar.bz2 |
struct: pack/unpack binary structs; fcntl: fcntl(), ioctl().
Diffstat (limited to 'Modules/structmodule.c')
-rw-r--r-- | Modules/structmodule.c | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/Modules/structmodule.c b/Modules/structmodule.c new file mode 100644 index 0000000..61122e4 --- /dev/null +++ b/Modules/structmodule.c @@ -0,0 +1,447 @@ +/*********************************************************** +Copyright 1991, 1992 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 */ + +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)) + + +/* 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': + *(double*)res = 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; +} + + +/* 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': + v = newfloatobject(*(double*)str); + 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 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"); +} |