blob: 61122e47a0e795ab6013f53c27472c7621673e03 [file] [log] [blame]
Guido van Rossum02975121992-08-17 08:55:12 +00001/***********************************************************
2Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
3Netherlands.
4
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':
293 *(double*)res = fval;
294 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
320/* unpack(fmt, string) --> (v1, v2, ...) */
321
322static object *
323struct_unpack(self, args)
324 object *self; /* Not used */
325 object *args;
326{
327 char *str, *start, *fmt, *s;
328 char c;
329 int len, size, num, x;
330 object *res, *v;
331
332 if (!getargs(args, "(ss#)", &fmt, &start, &len))
333 return NULL;
334 size = calcsize(fmt);
335 if (size != len) {
336 err_setstr(StructError, "unpack str size does not match fmt");
337 return NULL;
338 }
339 res = newlistobject(0);
340 if (res == NULL)
341 return NULL;
342 str = start;
343 s = fmt;
344 while ((c = *s++) != '\0') {
345 if ('0' <= c && c <= '9') {
346 num = c - '0';
347 while ('0' <= (c = *s++) && c <= '9')
348 num = num*10 + (c - '0');
349 if (c == '\0')
350 break;
351 }
352 else
353 num = 1;
354
355 str = start + align((int)(str-start), c);
356
357 while (--num >= 0) {
358 switch (c) {
359
360 case 'x':
361 str++;
362 continue;
363
364 case 'b':
365 x = *str++;
366 if (x >= 128)
367 x -= 256;
368 v = newintobject((long)x);
369 break;
370
371 case 'c':
372 v = newsizedstringobject(str, 1);
373 str++;
374 break;
375
376 case 'h':
377 v = newintobject((long)*(short*)str);
378 str += sizeof(short);
379 break;
380
381 case 'i':
382 v = newintobject((long)*(int*)str);
383 str += sizeof(int);
384 break;
385
386 case 'l':
387 v = newintobject(*(long*)str);
388 str += sizeof(long);
389 break;
390
391 case 'f':
392 v = newfloatobject((double)*(float*)str);
393 str += sizeof(float);
394 break;
395
396 case 'd':
397 v = newfloatobject(*(double*)str);
398 str += sizeof(double);
399 break;
400
401 default:
402 err_setstr(StructError, "bad char in fmt");
403 goto fail;
404
405 }
406 if (v == NULL || addlistitem(res, v) < 0)
407 goto fail;
408 DECREF(v);
409 }
410 }
411
412 return res;
413
414 fail:
415 DECREF(res);
416 return NULL;
417}
418
419/* List of functions */
420
421static struct methodlist struct_methods[] = {
422 {"calcsize", struct_calcsize},
423 {"pack", struct_pack, 1/*varargs*/},
424 {"unpack", struct_unpack},
425 {NULL, NULL} /* sentinel */
426};
427
428
429/* Module initialization */
430
431void
432initstruct()
433{
434 object *m, *d;
435
436 /* Create the module and add the functions */
437 m = initmodule("struct", struct_methods);
438
439 /* Add some symbolic constants to the module */
440 d = getmoduledict(m);
441 StructError = newstringobject("struct.error");
442 dictinsert(d, "error", StructError);
443
444 /* Check for errors */
445 if (err_occurred())
446 fatal("can't initialize module struct");
447}