blob: 649f3307107e2cbcaf23f2df052e77a98f6df18e [file] [log] [blame]
Guido van Rossum02975121992-08-17 08:55:12 +00001/***********************************************************
Guido van Rossum524b5881995-01-04 19:10:35 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum02975121992-08-17 08:55:12 +00004
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* struct module -- pack values into and (out of) strings */
26
27#include "allobjects.h"
28#include "modsupport.h"
29
30static object *StructError;
31
32
33/* Define various structs to figure out the alignments of types */
34
Jack Jansen971e1df1995-02-02 14:29:10 +000035#ifdef __MWERKS__
36/*
37** XXXX We have a problem here. There are no unique alignment rules
38** on the PowerPC mac.
39*/
40#ifdef __powerc
41#pragma options align=mac68k
42#endif
43#endif /* __MWERKS__ */
44
Guido van Rossum02975121992-08-17 08:55:12 +000045typedef struct { char c; short x; } s_short;
46typedef struct { char c; int x; } s_int;
47typedef struct { char c; long x; } s_long;
48typedef struct { char c; float x; } s_float;
49typedef struct { char c; double x; } s_double;
50
51#define SHORT_ALIGN (sizeof(s_short) - sizeof(short))
52#define INT_ALIGN (sizeof(s_int) - sizeof(int))
53#define LONG_ALIGN (sizeof(s_long) - sizeof(long))
54#define FLOAT_ALIGN (sizeof(s_float) - sizeof(float))
55#define DOUBLE_ALIGN (sizeof(s_double) - sizeof(double))
56
Jack Jansen971e1df1995-02-02 14:29:10 +000057#ifdef __powerc
58#pragma options align=reset
59#endif
60
Guido van Rossum02975121992-08-17 08:55:12 +000061
62/* Align a size according to a format code */
63
64static int
65align(size, c)
66 int size;
67 int c;
68{
69 int a;
70
71 switch (c) {
72 case 'h': a = SHORT_ALIGN; break;
73 case 'i': a = INT_ALIGN; break;
74 case 'l': a = LONG_ALIGN; break;
75 case 'f': a = FLOAT_ALIGN; break;
76 case 'd': a = DOUBLE_ALIGN; break;
77 default: return size;
78 }
79 return (size + a - 1) / a * a;
80}
81
82
83/* calculate the size of a format string */
84
85static int
86calcsize(fmt)
87 char *fmt;
88{
89 char *s;
90 char c;
91 int size, num, itemsize, x;
92
93 s = fmt;
94 size = 0;
95 while ((c = *s++) != '\0') {
96 if ('0' <= c && c <= '9') {
97 num = c - '0';
98 while ('0' <= (c = *s++) && c <= '9') {
99 x = num*10 + (c - '0');
100 if (x/10 != num) {
101 err_setstr(StructError,
102 "int overflow in fmt");
103 return -1;
104 }
105 num = x;
106 }
107 if (c == '\0')
108 break;
109 }
110 else
111 num = 1;
112
113 size = align(size, c);
114
115 switch (c) {
116
117 case 'x': /* pad byte */
118 case 'b': /* byte-sized int */
119 case 'c': /* char */
120 itemsize = 1;
121 break;
122
123 case 'h': /* short ("half-size)" int */
124 itemsize = sizeof(short);
125 break;
126
127 case 'i': /* natural-size int */
128 itemsize = sizeof(int);
129 break;
130
131 case 'l': /* long int */
132 itemsize = sizeof(long);
133 break;
134
135 case 'f': /* float */
136 itemsize = sizeof(float);
137 break;
138
139 case 'd': /* double */
140 itemsize = sizeof(double);
141 break;
142
143 default:
144 err_setstr(StructError, "bad char in fmt");
145 return -1;
146
147 }
148
149 x = num * itemsize;
150 size += x;
151 if (x/itemsize != num || size < 0) {
152 err_setstr(StructError, "total struct size too long");
153 return -1;
154 }
155
156 }
157
158 return size;
159}
160
161
162/* pack(fmt, v1, v2, ...) --> string */
163
164static object *
165struct_calcsize(self, args)
166 object *self; /* Not used */
167 object *args;
168{
169 char *fmt;
170 int size;
171
172 if (!getargs(args, "s", &fmt))
173 return NULL;
174 size = calcsize(fmt);
175 if (size < 0)
176 return NULL;
177 return newintobject((long)size);
178}
179
180
181/* pack(fmt, v1, v2, ...) --> string */
182
183static object *
184struct_pack(self, args)
185 object *self; /* Not used */
186 object *args;
187{
188 object *format, *result, *v;
189 char *fmt;
190 int size, num;
191 int i, n;
192 char *s, *res, *restart;
193 char c;
194 long ival;
195 double fval;
196
197 if (args == NULL || !is_tupleobject(args) ||
198 (n = gettuplesize(args)) < 1) {
199 err_badarg();
200 return NULL;
201 }
202 format = gettupleitem(args, 0);
203 if (!getargs(format, "s", &fmt))
204 return NULL;
205 size = calcsize(fmt);
206 if (size < 0)
207 return NULL;
208 result = newsizedstringobject((char *)NULL, size);
209 if (result == NULL)
210 return NULL;
211
212 s = fmt;
213 i = 1;
214 res = restart = getstringvalue(result);
215
216 while ((c = *s++) != '\0') {
217 if ('0' <= c && c <= '9') {
218 num = c - '0';
219 while ('0' <= (c = *s++) && c <= '9')
220 num = num*10 + (c - '0');
221 if (c == '\0')
222 break;
223 }
224 else
225 num = 1;
226
227 res = restart + align((int)(res-restart), c);
228
229 while (--num >= 0) {
230 switch (c) {
231
232 case 'x': /* pad byte */
233 *res++ = '\0';
234 break;
235
236 case 'l':
237 case 'i':
238 case 'h':
239 case 'b':
240 if (i >= n) {
241 err_setstr(StructError,
242 "insufficient arguments to pack");
243 goto fail;
244 }
245 v = gettupleitem(args, i++);
246 if (!is_intobject(v)) {
247 err_setstr(StructError,
248 "bad argument type to pack");
249 goto fail;
250 }
251 ival = getintvalue(v);
252 switch (c) {
253 case 'b':
254 *res++ = ival;
255 break;
256 case 'h':
257 *(short*)res = ival;
258 res += sizeof(short);
259 break;
260 case 'i':
261 *(int*)res = ival;
262 res += sizeof(int);
263 break;
264 case 'l':
265 *(long*)res = ival;
266 res += sizeof(long);
267 break;
268 }
269 break;
270
271 case 'c':
272 if (i >= n) {
273 err_setstr(StructError,
274 "insufficient arguments to pack");
275 goto fail;
276 }
277 v = gettupleitem(args, i++);
278 if (!is_stringobject(v) ||
279 getstringsize(v) != 1) {
280 err_setstr(StructError,
281 "bad argument type to pack");
282 goto fail;
283 }
284 *res++ = getstringvalue(v)[0];
285 break;
286
287 case 'd':
288 case 'f':
289 if (i >= n) {
290 err_setstr(StructError,
291 "insufficient arguments to pack");
292 goto fail;
293 }
294 v = gettupleitem(args, i++);
295 if (!is_floatobject(v)) {
296 err_setstr(StructError,
297 "bad argument type to pack");
298 goto fail;
299 }
300 fval = getfloatvalue(v);
301 switch (c) {
302 case 'f':
303 *(float*)res = (float)fval;
304 res += sizeof(float);
305 break;
306 case 'd':
Guido van Rossum524b5881995-01-04 19:10:35 +0000307 memcpy(res, (char*)&fval, sizeof fval);
Guido van Rossum02975121992-08-17 08:55:12 +0000308 res += sizeof(double);
309 break;
310 }
311 break;
312
313 default:
314 err_setstr(StructError, "bad char in fmt");
315 goto fail;
316
317 }
318 }
319 }
320
321 if (i < n) {
322 err_setstr(StructError, "too many arguments for pack fmt");
323 goto fail;
324 }
325
326 return result;
327
328 fail:
329 DECREF(result);
330 return NULL;
331}
332
333
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000334/* Helper to convert a list to a tuple */
335
336static object *
337totuple(list)
338 object *list;
339{
340 int len = getlistsize(list);
341 object *tuple = newtupleobject(len);
342 if (tuple != NULL) {
343 int i;
344 for (i = 0; i < len; i++) {
345 object *v = getlistitem(list, i);
346 INCREF(v);
347 settupleitem(tuple, i, v);
348 }
349 }
350 DECREF(list);
351 return tuple;
352}
353
354
Guido van Rossum02975121992-08-17 08:55:12 +0000355/* unpack(fmt, string) --> (v1, v2, ...) */
356
357static object *
358struct_unpack(self, args)
359 object *self; /* Not used */
360 object *args;
361{
362 char *str, *start, *fmt, *s;
363 char c;
364 int len, size, num, x;
365 object *res, *v;
366
367 if (!getargs(args, "(ss#)", &fmt, &start, &len))
368 return NULL;
369 size = calcsize(fmt);
370 if (size != len) {
371 err_setstr(StructError, "unpack str size does not match fmt");
372 return NULL;
373 }
374 res = newlistobject(0);
375 if (res == NULL)
376 return NULL;
377 str = start;
378 s = fmt;
379 while ((c = *s++) != '\0') {
380 if ('0' <= c && c <= '9') {
381 num = c - '0';
382 while ('0' <= (c = *s++) && c <= '9')
383 num = num*10 + (c - '0');
384 if (c == '\0')
385 break;
386 }
387 else
388 num = 1;
389
390 str = start + align((int)(str-start), c);
391
392 while (--num >= 0) {
393 switch (c) {
394
395 case 'x':
396 str++;
397 continue;
398
399 case 'b':
400 x = *str++;
401 if (x >= 128)
402 x -= 256;
403 v = newintobject((long)x);
404 break;
405
406 case 'c':
407 v = newsizedstringobject(str, 1);
408 str++;
409 break;
410
411 case 'h':
412 v = newintobject((long)*(short*)str);
413 str += sizeof(short);
414 break;
415
416 case 'i':
417 v = newintobject((long)*(int*)str);
418 str += sizeof(int);
419 break;
420
421 case 'l':
422 v = newintobject(*(long*)str);
423 str += sizeof(long);
424 break;
425
426 case 'f':
427 v = newfloatobject((double)*(float*)str);
428 str += sizeof(float);
429 break;
430
431 case 'd':
Guido van Rossum524b5881995-01-04 19:10:35 +0000432 {
433 double d;
434 memcpy((char *)&d, str, sizeof d);
435 v = newfloatobject(d);
Guido van Rossum02975121992-08-17 08:55:12 +0000436 str += sizeof(double);
437 break;
Guido van Rossum524b5881995-01-04 19:10:35 +0000438 }
Guido van Rossum02975121992-08-17 08:55:12 +0000439
440 default:
441 err_setstr(StructError, "bad char in fmt");
442 goto fail;
443
444 }
445 if (v == NULL || addlistitem(res, v) < 0)
446 goto fail;
447 DECREF(v);
448 }
449 }
450
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000451 return totuple(res);
Guido van Rossum02975121992-08-17 08:55:12 +0000452
453 fail:
454 DECREF(res);
455 return NULL;
456}
457
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000458
Guido van Rossum02975121992-08-17 08:55:12 +0000459/* List of functions */
460
461static struct methodlist struct_methods[] = {
462 {"calcsize", struct_calcsize},
463 {"pack", struct_pack, 1/*varargs*/},
464 {"unpack", struct_unpack},
465 {NULL, NULL} /* sentinel */
466};
467
468
469/* Module initialization */
470
471void
472initstruct()
473{
474 object *m, *d;
475
476 /* Create the module and add the functions */
477 m = initmodule("struct", struct_methods);
478
479 /* Add some symbolic constants to the module */
480 d = getmoduledict(m);
481 StructError = newstringobject("struct.error");
482 dictinsert(d, "error", StructError);
483
484 /* Check for errors */
485 if (err_occurred())
486 fatal("can't initialize module struct");
487}