summaryrefslogtreecommitdiffstats
path: root/Modules/structmodule.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1992-08-17 08:55:12 (GMT)
committerGuido van Rossum <guido@python.org>1992-08-17 08:55:12 (GMT)
commit0297512a08698cdee4bebe044a40b08b406398a8 (patch)
tree52ceb535f0f2b4068f1a5ce1f17c199477437b67 /Modules/structmodule.c
parent94390a4eaf48c3ddf91cdbf78fcf5db7b57972ec (diff)
downloadcpython-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.c447
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");
+}