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