blob: a0ecb675d026f8e9a390ed175dd07ad8b17fd295 [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
35typedef struct { char c; short x; } s_short;
36typedef struct { char c; int x; } s_int;
37typedef struct { char c; long x; } s_long;
38typedef struct { char c; float x; } s_float;
39typedef struct { char c; double x; } s_double;
40
41#define SHORT_ALIGN (sizeof(s_short) - sizeof(short))
42#define INT_ALIGN (sizeof(s_int) - sizeof(int))
43#define LONG_ALIGN (sizeof(s_long) - sizeof(long))
44#define FLOAT_ALIGN (sizeof(s_float) - sizeof(float))
45#define DOUBLE_ALIGN (sizeof(s_double) - sizeof(double))
46
47
48/* Align a size according to a format code */
49
50static int
51align(size, c)
52 int size;
53 int c;
54{
55 int a;
56
57 switch (c) {
58 case 'h': a = SHORT_ALIGN; break;
59 case 'i': a = INT_ALIGN; break;
60 case 'l': a = LONG_ALIGN; break;
61 case 'f': a = FLOAT_ALIGN; break;
62 case 'd': a = DOUBLE_ALIGN; break;
63 default: return size;
64 }
65 return (size + a - 1) / a * a;
66}
67
68
69/* calculate the size of a format string */
70
71static int
72calcsize(fmt)
73 char *fmt;
74{
75 char *s;
76 char c;
77 int size, num, itemsize, x;
78
79 s = fmt;
80 size = 0;
81 while ((c = *s++) != '\0') {
82 if ('0' <= c && c <= '9') {
83 num = c - '0';
84 while ('0' <= (c = *s++) && c <= '9') {
85 x = num*10 + (c - '0');
86 if (x/10 != num) {
87 err_setstr(StructError,
88 "int overflow in fmt");
89 return -1;
90 }
91 num = x;
92 }
93 if (c == '\0')
94 break;
95 }
96 else
97 num = 1;
98
99 size = align(size, c);
100
101 switch (c) {
102
103 case 'x': /* pad byte */
104 case 'b': /* byte-sized int */
105 case 'c': /* char */
106 itemsize = 1;
107 break;
108
109 case 'h': /* short ("half-size)" int */
110 itemsize = sizeof(short);
111 break;
112
113 case 'i': /* natural-size int */
114 itemsize = sizeof(int);
115 break;
116
117 case 'l': /* long int */
118 itemsize = sizeof(long);
119 break;
120
121 case 'f': /* float */
122 itemsize = sizeof(float);
123 break;
124
125 case 'd': /* double */
126 itemsize = sizeof(double);
127 break;
128
129 default:
130 err_setstr(StructError, "bad char in fmt");
131 return -1;
132
133 }
134
135 x = num * itemsize;
136 size += x;
137 if (x/itemsize != num || size < 0) {
138 err_setstr(StructError, "total struct size too long");
139 return -1;
140 }
141
142 }
143
144 return size;
145}
146
147
148/* pack(fmt, v1, v2, ...) --> string */
149
150static object *
151struct_calcsize(self, args)
152 object *self; /* Not used */
153 object *args;
154{
155 char *fmt;
156 int size;
157
158 if (!getargs(args, "s", &fmt))
159 return NULL;
160 size = calcsize(fmt);
161 if (size < 0)
162 return NULL;
163 return newintobject((long)size);
164}
165
166
167/* pack(fmt, v1, v2, ...) --> string */
168
169static object *
170struct_pack(self, args)
171 object *self; /* Not used */
172 object *args;
173{
174 object *format, *result, *v;
175 char *fmt;
176 int size, num;
177 int i, n;
178 char *s, *res, *restart;
179 char c;
180 long ival;
181 double fval;
182
183 if (args == NULL || !is_tupleobject(args) ||
184 (n = gettuplesize(args)) < 1) {
185 err_badarg();
186 return NULL;
187 }
188 format = gettupleitem(args, 0);
189 if (!getargs(format, "s", &fmt))
190 return NULL;
191 size = calcsize(fmt);
192 if (size < 0)
193 return NULL;
194 result = newsizedstringobject((char *)NULL, size);
195 if (result == NULL)
196 return NULL;
197
198 s = fmt;
199 i = 1;
200 res = restart = getstringvalue(result);
201
202 while ((c = *s++) != '\0') {
203 if ('0' <= c && c <= '9') {
204 num = c - '0';
205 while ('0' <= (c = *s++) && c <= '9')
206 num = num*10 + (c - '0');
207 if (c == '\0')
208 break;
209 }
210 else
211 num = 1;
212
213 res = restart + align((int)(res-restart), c);
214
215 while (--num >= 0) {
216 switch (c) {
217
218 case 'x': /* pad byte */
219 *res++ = '\0';
220 break;
221
222 case 'l':
223 case 'i':
224 case 'h':
225 case 'b':
226 if (i >= n) {
227 err_setstr(StructError,
228 "insufficient arguments to pack");
229 goto fail;
230 }
231 v = gettupleitem(args, i++);
232 if (!is_intobject(v)) {
233 err_setstr(StructError,
234 "bad argument type to pack");
235 goto fail;
236 }
237 ival = getintvalue(v);
238 switch (c) {
239 case 'b':
240 *res++ = ival;
241 break;
242 case 'h':
243 *(short*)res = ival;
244 res += sizeof(short);
245 break;
246 case 'i':
247 *(int*)res = ival;
248 res += sizeof(int);
249 break;
250 case 'l':
251 *(long*)res = ival;
252 res += sizeof(long);
253 break;
254 }
255 break;
256
257 case 'c':
258 if (i >= n) {
259 err_setstr(StructError,
260 "insufficient arguments to pack");
261 goto fail;
262 }
263 v = gettupleitem(args, i++);
264 if (!is_stringobject(v) ||
265 getstringsize(v) != 1) {
266 err_setstr(StructError,
267 "bad argument type to pack");
268 goto fail;
269 }
270 *res++ = getstringvalue(v)[0];
271 break;
272
273 case 'd':
274 case 'f':
275 if (i >= n) {
276 err_setstr(StructError,
277 "insufficient arguments to pack");
278 goto fail;
279 }
280 v = gettupleitem(args, i++);
281 if (!is_floatobject(v)) {
282 err_setstr(StructError,
283 "bad argument type to pack");
284 goto fail;
285 }
286 fval = getfloatvalue(v);
287 switch (c) {
288 case 'f':
289 *(float*)res = (float)fval;
290 res += sizeof(float);
291 break;
292 case 'd':
Guido van Rossum524b5881995-01-04 19:10:35 +0000293 memcpy(res, (char*)&fval, sizeof fval);
Guido van Rossum02975121992-08-17 08:55:12 +0000294 res += sizeof(double);
295 break;
296 }
297 break;
298
299 default:
300 err_setstr(StructError, "bad char in fmt");
301 goto fail;
302
303 }
304 }
305 }
306
307 if (i < n) {
308 err_setstr(StructError, "too many arguments for pack fmt");
309 goto fail;
310 }
311
312 return result;
313
314 fail:
315 DECREF(result);
316 return NULL;
317}
318
319
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000320/* Helper to convert a list to a tuple */
321
322static object *
323totuple(list)
324 object *list;
325{
326 int len = getlistsize(list);
327 object *tuple = newtupleobject(len);
328 if (tuple != NULL) {
329 int i;
330 for (i = 0; i < len; i++) {
331 object *v = getlistitem(list, i);
332 INCREF(v);
333 settupleitem(tuple, i, v);
334 }
335 }
336 DECREF(list);
337 return tuple;
338}
339
340
Guido van Rossum02975121992-08-17 08:55:12 +0000341/* unpack(fmt, string) --> (v1, v2, ...) */
342
343static object *
344struct_unpack(self, args)
345 object *self; /* Not used */
346 object *args;
347{
348 char *str, *start, *fmt, *s;
349 char c;
350 int len, size, num, x;
351 object *res, *v;
352
353 if (!getargs(args, "(ss#)", &fmt, &start, &len))
354 return NULL;
355 size = calcsize(fmt);
356 if (size != len) {
357 err_setstr(StructError, "unpack str size does not match fmt");
358 return NULL;
359 }
360 res = newlistobject(0);
361 if (res == NULL)
362 return NULL;
363 str = start;
364 s = fmt;
365 while ((c = *s++) != '\0') {
366 if ('0' <= c && c <= '9') {
367 num = c - '0';
368 while ('0' <= (c = *s++) && c <= '9')
369 num = num*10 + (c - '0');
370 if (c == '\0')
371 break;
372 }
373 else
374 num = 1;
375
376 str = start + align((int)(str-start), c);
377
378 while (--num >= 0) {
379 switch (c) {
380
381 case 'x':
382 str++;
383 continue;
384
385 case 'b':
386 x = *str++;
387 if (x >= 128)
388 x -= 256;
389 v = newintobject((long)x);
390 break;
391
392 case 'c':
393 v = newsizedstringobject(str, 1);
394 str++;
395 break;
396
397 case 'h':
398 v = newintobject((long)*(short*)str);
399 str += sizeof(short);
400 break;
401
402 case 'i':
403 v = newintobject((long)*(int*)str);
404 str += sizeof(int);
405 break;
406
407 case 'l':
408 v = newintobject(*(long*)str);
409 str += sizeof(long);
410 break;
411
412 case 'f':
413 v = newfloatobject((double)*(float*)str);
414 str += sizeof(float);
415 break;
416
417 case 'd':
Guido van Rossum524b5881995-01-04 19:10:35 +0000418 {
419 double d;
420 memcpy((char *)&d, str, sizeof d);
421 v = newfloatobject(d);
Guido van Rossum02975121992-08-17 08:55:12 +0000422 str += sizeof(double);
423 break;
Guido van Rossum524b5881995-01-04 19:10:35 +0000424 }
Guido van Rossum02975121992-08-17 08:55:12 +0000425
426 default:
427 err_setstr(StructError, "bad char in fmt");
428 goto fail;
429
430 }
431 if (v == NULL || addlistitem(res, v) < 0)
432 goto fail;
433 DECREF(v);
434 }
435 }
436
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000437 return totuple(res);
Guido van Rossum02975121992-08-17 08:55:12 +0000438
439 fail:
440 DECREF(res);
441 return NULL;
442}
443
Guido van Rossum90ddb7b1992-08-19 16:44:15 +0000444
Guido van Rossum02975121992-08-17 08:55:12 +0000445/* List of functions */
446
447static struct methodlist struct_methods[] = {
448 {"calcsize", struct_calcsize},
449 {"pack", struct_pack, 1/*varargs*/},
450 {"unpack", struct_unpack},
451 {NULL, NULL} /* sentinel */
452};
453
454
455/* Module initialization */
456
457void
458initstruct()
459{
460 object *m, *d;
461
462 /* Create the module and add the functions */
463 m = initmodule("struct", struct_methods);
464
465 /* Add some symbolic constants to the module */
466 d = getmoduledict(m);
467 StructError = newstringobject("struct.error");
468 dictinsert(d, "error", StructError);
469
470 /* Check for errors */
471 if (err_occurred())
472 fatal("can't initialize module struct");
473}