(find_barrier): Set si_limit to 1018 instead of 1020, and
[official-gcc.git] / gcc / objc / archive.c
blobe9bdcbd17f1797c44662b28d75e56299d1307eb8
1 /* GNU Objective C Runtime archiving
2 Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 details.
16 You should have received a copy of the GNU General Public License along with
17 GNU CC; see the file COPYING. If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* As a special exception, if you link this library with files compiled with
22 GCC to produce an executable, this does not cause the resulting executable
23 to be covered by the GNU General Public License. This exception does not
24 however invalidate any other reasons why the executable file might be
25 covered by the GNU General Public License. */
27 #include "runtime.h"
28 #include "typedstream.h"
29 #include "encoding.h"
31 extern int fflush(FILE*);
33 #define ROUND(V, A) \
34 ({ typeof(V) __v=(V); typeof(A) __a=(A); \
35 __a*((__v+__a-1)/__a); })
37 #define PTR2LONG(P) (((char*)(P))-(char*)0)
38 #define LONG2PTR(L) (((char*)0)+(L))
40 #define __objc_fatal(format, args...) \
41 { fprintf(stderr, "archiving: "); \
42 fprintf(stderr, format, ## args); \
43 fprintf(stderr, "\n"); abort(); }
45 /* Declare some functions... */
47 static int
48 objc_read_class (struct objc_typed_stream* stream, Class* class);
50 int objc_sizeof_type(const char* type);
52 static int
53 objc_write_use_common (struct objc_typed_stream* stream, unsigned long key);
55 static int
56 objc_write_register_common (struct objc_typed_stream* stream,
57 unsigned long key);
59 static int
60 objc_write_class (struct objc_typed_stream* stream,
61 struct objc_class* class);
63 const char* objc_skip_type (const char* type);
65 static void __objc_finish_write_root_object(struct objc_typed_stream*);
66 static void __objc_finish_read_root_object(struct objc_typed_stream*);
68 static __inline__ int
69 __objc_code_unsigned_char (unsigned char* buf, unsigned char val)
71 if ((val&_B_VALUE) == val)
73 buf[0] = val|_B_SINT;
74 return 1;
76 else
78 buf[0] = _B_NINT|0x01;
79 buf[1] = val;
80 return 2;
84 int
85 objc_write_unsigned_char (struct objc_typed_stream* stream,
86 unsigned char value)
88 unsigned char buf[sizeof (unsigned char)+1];
89 int len = __objc_code_unsigned_char (buf, value);
90 return (*stream->write)(stream->physical, buf, len);
93 static __inline__ int
94 __objc_code_char (unsigned char* buf, char val)
96 if (val >= 0)
97 return __objc_code_unsigned_char (buf, val);
98 else
100 buf[0] = _B_NINT|_B_SIGN|0x01;
101 buf[1] = -val;
102 return 2;
107 objc_write_char (struct objc_typed_stream* stream, char value)
109 unsigned char buf[sizeof (char)+1];
110 int len = __objc_code_char (buf, value);
111 return (*stream->write)(stream->physical, buf, len);
114 static __inline__ int
115 __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
117 if ((val&_B_VALUE) == val)
119 buf[0] = val|_B_SINT;
120 return 1;
122 else
124 int c, b;
126 buf[0] = _B_NINT;
128 for (c= sizeof(short); c != 0; c -= 1)
129 if (((val>>(8*(c-1)))%0x100) != 0)
130 break;
132 buf[0] |= c;
134 for (b = 1; c != 0; c--, b++)
136 buf[b] = (val >> (8*(c-1)))%0x100;
139 return b;
144 objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
146 unsigned char buf[sizeof (unsigned short)+1];
147 int len = __objc_code_unsigned_short (buf, value);
148 return (*stream->write)(stream->physical, buf, len);
151 static __inline__ int
152 __objc_code_short (unsigned char* buf, short val)
154 int sign = (val < 0);
155 int size = __objc_code_unsigned_short (buf, sign ? -val : val);
156 if (sign)
157 buf[0] |= _B_SIGN;
158 return size;
162 objc_write_short (struct objc_typed_stream* stream, short value)
164 unsigned char buf[sizeof (short)+1];
165 int len = __objc_code_short (buf, value);
166 return (*stream->write)(stream->physical, buf, len);
170 static __inline__ int
171 __objc_code_unsigned_int (unsigned char* buf, unsigned int val)
173 if ((val&_B_VALUE) == val)
175 buf[0] = val|_B_SINT;
176 return 1;
178 else
180 int c, b;
182 buf[0] = _B_NINT;
184 for (c= sizeof(int); c != 0; c -= 1)
185 if (((val>>(8*(c-1)))%0x100) != 0)
186 break;
188 buf[0] |= c;
190 for (b = 1; c != 0; c--, b++)
192 buf[b] = (val >> (8*(c-1)))%0x100;
195 return b;
200 objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
202 unsigned char buf[sizeof(unsigned int)+1];
203 int len = __objc_code_unsigned_int (buf, value);
204 return (*stream->write)(stream->physical, buf, len);
207 static __inline__ int
208 __objc_code_int (unsigned char* buf, int val)
210 int sign = (val < 0);
211 int size = __objc_code_unsigned_int (buf, sign ? -val : val);
212 if (sign)
213 buf[0] |= _B_SIGN;
214 return size;
218 objc_write_int (struct objc_typed_stream* stream, int value)
220 unsigned char buf[sizeof(int)+1];
221 int len = __objc_code_int (buf, value);
222 return (*stream->write)(stream->physical, buf, len);
225 static __inline__ int
226 __objc_code_unsigned_long (unsigned char* buf, unsigned long val)
228 if ((val&_B_VALUE) == val)
230 buf[0] = val|_B_SINT;
231 return 1;
233 else
235 int c, b;
237 buf[0] = _B_NINT;
239 for (c= sizeof(long); c != 0; c -= 1)
240 if (((val>>(8*(c-1)))%0x100) != 0)
241 break;
243 buf[0] |= c;
245 for (b = 1; c != 0; c--, b++)
247 buf[b] = (val >> (8*(c-1)))%0x100;
250 return b;
255 objc_write_unsigned_long (struct objc_typed_stream* stream, unsigned long value)
257 unsigned char buf[sizeof(unsigned long)+1];
258 int len = __objc_code_unsigned_long (buf, value);
259 return (*stream->write)(stream->physical, buf, len);
262 static __inline__ int
263 __objc_code_long (unsigned char* buf, long val)
265 int sign = (val < 0);
266 int size = __objc_code_unsigned_long (buf, sign ? -val : val);
267 if (sign)
268 buf[0] |= _B_SIGN;
269 return size;
273 objc_write_long (struct objc_typed_stream* stream, long value)
275 unsigned char buf[sizeof(long)+1];
276 int len = __objc_code_long (buf, value);
277 return (*stream->write)(stream->physical, buf, len);
282 objc_write_string (struct objc_typed_stream* stream,
283 const unsigned char* string, unsigned int nbytes)
285 unsigned char buf[sizeof(unsigned int)+1];
286 int len = __objc_code_unsigned_int (buf, nbytes);
288 if ((buf[0]&_B_CODE) == _B_SINT)
289 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
291 else /* _B_NINT */
292 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
294 if ((*stream->write)(stream->physical, buf, len) != 0)
295 return (*stream->write)(stream->physical, string, nbytes);
296 else
297 return 0;
301 objc_write_string_atomic (struct objc_typed_stream* stream,
302 unsigned char* string, unsigned int nbytes)
304 unsigned long key;
305 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string))))
306 return objc_write_use_common (stream, key);
307 else
309 int length;
310 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string);
311 if ((length = objc_write_register_common (stream, key)))
312 return objc_write_string (stream, string, nbytes);
313 return length;
317 static int
318 objc_write_register_common (struct objc_typed_stream* stream, unsigned long key)
320 unsigned char buf[sizeof (unsigned long)+2];
321 int len = __objc_code_unsigned_long (buf+1, key);
322 if (len == 1)
324 buf[0] = _B_RCOMM|0x01;
325 buf[1] &= _B_VALUE;
326 return (*stream->write)(stream->physical, buf, len+1);
328 else
330 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
331 return (*stream->write)(stream->physical, buf+1, len);
335 static int
336 objc_write_use_common (struct objc_typed_stream* stream, unsigned long key)
338 unsigned char buf[sizeof (unsigned long)+2];
339 int len = __objc_code_unsigned_long (buf+1, key);
340 if (len == 1)
342 buf[0] = _B_UCOMM|0x01;
343 buf[1] &= _B_VALUE;
344 return (*stream->write)(stream->physical, buf, 2);
346 else
348 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
349 return (*stream->write)(stream->physical, buf+1, len);
353 static __inline__ int
354 __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
356 if (code <= _B_VALUE)
358 unsigned char buf = code|_B_EXT;
359 return (*stream->write)(stream->physical, &buf, 1);
361 else
362 abort();
365 __inline__ int
366 __objc_write_object (struct objc_typed_stream* stream, id object)
368 unsigned char buf = '\0';
369 SEL write_sel = sel_get_any_uid ("write:");
370 if (object)
372 __objc_write_extension (stream, _BX_OBJECT);
373 objc_write_class (stream, object->class_pointer);
374 (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
375 return (*stream->write)(stream->physical, &buf, 1);
377 else
378 return objc_write_use_common(stream, 0);
381 int
382 objc_write_object_reference (struct objc_typed_stream* stream, id object)
384 unsigned long key;
385 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
386 return objc_write_use_common (stream, key);
388 __objc_write_extension (stream, _BX_OBJREF);
389 return objc_write_unsigned_long (stream, PTR2LONG (object));
392 int
393 objc_write_root_object (struct objc_typed_stream* stream, id object)
395 int len;
396 if (stream->writing_root_p)
397 __objc_fatal ("objc_write_root_object called recursively")
398 else
400 stream->writing_root_p = 1;
401 __objc_write_extension (stream, _BX_OBJROOT);
402 if((len = objc_write_object (stream, object)))
403 __objc_finish_write_root_object(stream);
404 stream->writing_root_p = 0;
406 return len;
409 int
410 objc_write_object (struct objc_typed_stream* stream, id object)
412 unsigned long key;
413 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
414 return objc_write_use_common (stream, key);
416 else if (object == nil)
417 return objc_write_use_common(stream, 0);
419 else
421 int length;
422 hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object);
423 if ((length = objc_write_register_common (stream, key)))
424 return __objc_write_object (stream, object);
425 return length;
429 #ifdef __alpha__
430 extern int atoi (const char*);
431 extern size_t strlen(const char*);
432 extern size_t strcpy(char*, const char*);
433 #endif
435 __inline__ int
436 __objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
438 __objc_write_extension (stream, _BX_CLASS);
439 objc_write_string_atomic(stream, (char*)class->name,
440 strlen((char*)class->name));
441 return objc_write_unsigned_long (stream, class->version);
445 static int
446 objc_write_class (struct objc_typed_stream* stream,
447 struct objc_class* class)
449 unsigned long key;
450 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class))))
451 return objc_write_use_common (stream, key);
452 else
454 int length;
455 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class);
456 if ((length = objc_write_register_common (stream, key)))
457 return __objc_write_class (stream, class);
458 return length;
463 __inline__ int
464 __objc_write_selector (struct objc_typed_stream* stream, SEL selector)
466 const char* sel_name;
467 __objc_write_extension (stream, _BX_SEL);
468 /* to handle NULL selectors */
469 if ((SEL)0 == selector)
470 return objc_write_string (stream, "", 0);
471 sel_name = sel_get_name (selector);
472 return objc_write_string (stream, sel_name, strlen ((char*)sel_name));
475 int
476 objc_write_selector (struct objc_typed_stream* stream, SEL selector)
478 const char* sel_name;
479 unsigned long key;
481 /* to handle NULL selectors */
482 if ((SEL)0 == selector)
483 return __objc_write_selector (stream, selector);
485 sel_name = sel_get_name (selector);
486 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name))))
487 return objc_write_use_common (stream, key);
488 else
490 int length;
491 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
492 if ((length = objc_write_register_common (stream, key)))
493 return __objc_write_selector (stream, selector);
494 return length;
501 ** Read operations
504 __inline__ int
505 objc_read_char (struct objc_typed_stream* stream, char* val)
507 unsigned char buf;
508 int len;
509 len = (*stream->read)(stream->physical, &buf, 1);
510 if (len != 0)
512 if ((buf & _B_CODE) == _B_SINT)
513 (*val) = (buf & _B_VALUE);
515 else if ((buf & _B_NUMBER) == 1)
517 len = (*stream->read)(stream->physical, val, 1);
518 if (buf&_B_SIGN)
519 (*val) = -1*(*val);
522 else
523 __objc_fatal("expected 8bit signed int, got %dbit int",
524 (int)(buf&_B_NUMBER)*8);
526 return len;
530 __inline__ int
531 objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
533 unsigned char buf;
534 int len;
535 if ((len = (*stream->read)(stream->physical, &buf, 1)))
537 if ((buf & _B_CODE) == _B_SINT)
538 (*val) = (buf & _B_VALUE);
540 else if ((buf & _B_NUMBER) == 1)
541 len = (*stream->read)(stream->physical, val, 1);
543 else
544 __objc_fatal("expected 8bit unsigned int, got %dbit int",
545 (int)(buf&_B_NUMBER)*8);
547 return len;
550 __inline__ int
551 objc_read_short (struct objc_typed_stream* stream, short* value)
553 unsigned char buf[sizeof(short)+1];
554 int len;
555 if ((len = (*stream->read)(stream->physical, buf, 1)))
557 if ((buf[0] & _B_CODE) == _B_SINT)
558 (*value) = (buf[0] & _B_VALUE);
560 else
562 int pos = 1;
563 int nbytes = buf[0] & _B_NUMBER;
564 if (nbytes > sizeof (short))
565 __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
566 len = (*stream->read)(stream->physical, buf+1, nbytes);
567 (*value) = 0;
568 while (pos <= nbytes)
569 (*value) = ((*value)*0x100) + buf[pos++];
570 if (buf[0] & _B_SIGN)
571 (*value) = -(*value);
574 return len;
577 __inline__ int
578 objc_read_unsigned_short (struct objc_typed_stream* stream,
579 unsigned short* value)
581 unsigned char buf[sizeof(unsigned short)+1];
582 int len;
583 if ((len = (*stream->read)(stream->physical, buf, 1)))
585 if ((buf[0] & _B_CODE) == _B_SINT)
586 (*value) = (buf[0] & _B_VALUE);
588 else
590 int pos = 1;
591 int nbytes = buf[0] & _B_NUMBER;
592 if (nbytes > sizeof (short))
593 __objc_fatal("expected short, got int or bigger");
594 len = (*stream->read)(stream->physical, buf+1, nbytes);
595 (*value) = 0;
596 while (pos <= nbytes)
597 (*value) = ((*value)*0x100) + buf[pos++];
600 return len;
604 __inline__ int
605 objc_read_int (struct objc_typed_stream* stream, int* value)
607 unsigned char buf[sizeof(int)+1];
608 int len;
609 if ((len = (*stream->read)(stream->physical, buf, 1)))
611 if ((buf[0] & _B_CODE) == _B_SINT)
612 (*value) = (buf[0] & _B_VALUE);
614 else
616 int pos = 1;
617 int nbytes = buf[0] & _B_NUMBER;
618 if (nbytes > sizeof (int))
619 __objc_fatal("expected int, got bigger");
620 len = (*stream->read)(stream->physical, buf+1, nbytes);
621 (*value) = 0;
622 while (pos <= nbytes)
623 (*value) = ((*value)*0x100) + buf[pos++];
624 if (buf[0] & _B_SIGN)
625 (*value) = -(*value);
628 return len;
631 __inline__ int
632 objc_read_long (struct objc_typed_stream* stream, long* value)
634 unsigned char buf[sizeof(long)+1];
635 int len;
636 if ((len = (*stream->read)(stream->physical, buf, 1)))
638 if ((buf[0] & _B_CODE) == _B_SINT)
639 (*value) = (buf[0] & _B_VALUE);
641 else
643 int pos = 1;
644 int nbytes = buf[0] & _B_NUMBER;
645 if (nbytes > sizeof (long))
646 __objc_fatal("expected long, got bigger");
647 len = (*stream->read)(stream->physical, buf+1, nbytes);
648 (*value) = 0;
649 while (pos <= nbytes)
650 (*value) = ((*value)*0x100) + buf[pos++];
651 if (buf[0] & _B_SIGN)
652 (*value) = -(*value);
655 return len;
658 __inline__ int
659 __objc_read_nbyte_uint (struct objc_typed_stream* stream,
660 unsigned int nbytes, unsigned int* val)
662 int len, pos = 0;
663 unsigned char buf[sizeof(unsigned int)+1];
665 if (nbytes > sizeof (int))
666 __objc_fatal("expected int, got bigger");
668 len = (*stream->read)(stream->physical, buf, nbytes);
669 (*val) = 0;
670 while (pos < nbytes)
671 (*val) = ((*val)*0x100) + buf[pos++];
672 return len;
676 __inline__ int
677 objc_read_unsigned_int (struct objc_typed_stream* stream,
678 unsigned int* value)
680 unsigned char buf[sizeof(unsigned int)+1];
681 int len;
682 if ((len = (*stream->read)(stream->physical, buf, 1)))
684 if ((buf[0] & _B_CODE) == _B_SINT)
685 (*value) = (buf[0] & _B_VALUE);
687 else
688 len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
691 return len;
695 __objc_read_nbyte_ulong (struct objc_typed_stream* stream,
696 unsigned int nbytes, unsigned long* val)
698 int len, pos = 0;
699 unsigned char buf[sizeof(unsigned long)+1];
701 if (nbytes > sizeof (long))
702 __objc_fatal("expected long, got bigger");
704 len = (*stream->read)(stream->physical, buf, nbytes);
705 (*val) = 0;
706 while (pos < nbytes)
707 (*val) = ((*val)*0x100) + buf[pos++];
708 return len;
712 __inline__ int
713 objc_read_unsigned_long (struct objc_typed_stream* stream,
714 unsigned long* value)
716 unsigned char buf[sizeof(unsigned long)+1];
717 int len;
718 if ((len = (*stream->read)(stream->physical, buf, 1)))
720 if ((buf[0] & _B_CODE) == _B_SINT)
721 (*value) = (buf[0] & _B_VALUE);
723 else
724 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
727 return len;
730 __inline__ int
731 objc_read_string (struct objc_typed_stream* stream,
732 char** string)
734 unsigned char buf[sizeof(unsigned int)+1];
735 int len;
736 if ((len = (*stream->read)(stream->physical, buf, 1)))
738 unsigned long key = 0;
740 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
742 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
743 len = (*stream->read)(stream->physical, buf, 1);
746 switch (buf[0]&_B_CODE) {
747 case _B_SSTR:
749 int length = buf[0]&_B_VALUE;
750 (*string) = (char*)__objc_xmalloc(length+1);
751 if (key)
752 hash_add (&stream->stream_table, LONG2PTR(key), *string);
753 len = (*stream->read)(stream->physical, *string, length);
754 (*string)[length] = '\0';
756 break;
758 case _B_UCOMM:
760 char *tmp;
761 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
762 tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
763 *string = __objc_xmalloc (strlen(tmp) + 1);
764 strcpy (*string, tmp);
766 break;
768 case _B_NSTR:
770 unsigned int nbytes = buf[0]&_B_VALUE;
771 len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
772 if (len) {
773 (*string) = (char*)__objc_xmalloc(nbytes+1);
774 if (key)
775 hash_add (&stream->stream_table, LONG2PTR(key), *string);
776 len = (*stream->read)(stream->physical, *string, nbytes);
777 (*string)[nbytes] = '\0';
780 break;
782 default:
783 __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
787 return len;
792 objc_read_object (struct objc_typed_stream* stream, id* object)
794 unsigned char buf[sizeof (unsigned int)];
795 int len;
796 if ((len = (*stream->read)(stream->physical, buf, 1)))
798 SEL read_sel = sel_get_any_uid ("read:");
799 unsigned long key = 0;
801 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
803 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
804 len = (*stream->read)(stream->physical, buf, 1);
807 if (buf[0] == (_B_EXT | _BX_OBJECT))
809 Class class;
811 /* get class */
812 len = objc_read_class (stream, &class);
814 /* create instance */
815 (*object) = class_create_instance(class);
817 /* register? */
818 if (key)
819 hash_add (&stream->object_table, LONG2PTR(key), *object);
821 /* send -read: */
822 if (__objc_responds_to (*object, read_sel))
823 (*get_imp(class, read_sel))(*object, read_sel, stream);
825 /* check null-byte */
826 len = (*stream->read)(stream->physical, buf, 1);
827 if (buf[0] != '\0')
828 __objc_fatal("expected null-byte, got opcode %c", buf[0]);
831 else if ((buf[0]&_B_CODE) == _B_UCOMM)
833 if (key)
834 __objc_fatal("cannot register use upcode...");
835 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
836 (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
839 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
841 struct objc_list* other;
842 len = objc_read_unsigned_long (stream, &key);
843 other = (struct objc_list*)hash_value_for_key (stream->object_refs, LONG2PTR(key));
844 hash_add (&stream->object_refs, LONG2PTR(key), (void*)list_cons(object, other));
847 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
849 if (key)
850 __objc_fatal("cannot register root object...");
851 len = objc_read_object (stream, object);
852 __objc_finish_read_root_object (stream);
855 else
856 __objc_fatal("expected object, got opcode %c", buf[0]);
858 return len;
861 static int
862 objc_read_class (struct objc_typed_stream* stream, Class* class)
864 unsigned char buf[sizeof (unsigned int)];
865 int len;
866 if ((len = (*stream->read)(stream->physical, buf, 1)))
868 unsigned long key = 0;
870 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
872 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
873 len = (*stream->read)(stream->physical, buf, 1);
876 if (buf[0] == (_B_EXT | _BX_CLASS))
878 char* class_name;
879 unsigned long version;
881 /* get class */
882 len = objc_read_string (stream, &class_name);
883 (*class) = objc_get_class(class_name);
884 free (class_name);
886 /* register */
887 if (key)
888 hash_add (&stream->stream_table, LONG2PTR(key), *class);
890 objc_read_unsigned_long(stream, &version);
891 hash_add (&stream->class_table, (*class)->name, (void*)version);
894 else if ((buf[0]&_B_CODE) == _B_UCOMM)
896 if (key)
897 __objc_fatal("cannot register use upcode...");
898 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
899 (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
900 if (!*class)
901 __objc_fatal("cannot find class for key %lu", key);
904 else
905 __objc_fatal("expected class, got opcode %c", buf[0]);
907 return len;
911 objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
913 unsigned char buf[sizeof (unsigned int)];
914 int len;
915 if ((len = (*stream->read)(stream->physical, buf, 1)))
917 unsigned long key = 0;
919 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
921 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
922 len = (*stream->read)(stream->physical, buf, 1);
925 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
927 char* selector_name;
929 /* get selector */
930 len = objc_read_string (stream, &selector_name);
931 /* To handle NULL selectors */
932 if (0 == strlen(selector_name))
934 (*selector) = (SEL)0;
935 return 0;
937 else
938 (*selector) = sel_get_any_uid(selector_name);
939 free (selector_name);
941 /* register */
942 if (key)
943 hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector);
946 else if ((buf[0]&_B_CODE) == _B_UCOMM)
948 if (key)
949 __objc_fatal("cannot register use upcode...");
950 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
951 (*selector) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
954 else
955 __objc_fatal("expected selector, got opcode %c", buf[0]);
957 return len;
961 ** USER LEVEL FUNCTIONS
965 ** Write one object, encoded in TYPE and pointed to by DATA to the
966 ** typed stream STREAM.
970 objc_write_type(TypedStream* stream, const char* type, const void* data)
972 switch(*type) {
973 case _C_ID:
974 return objc_write_object (stream, *(id*)data);
975 break;
977 case _C_CLASS:
978 return objc_write_class (stream, *(Class*)data);
979 break;
981 case _C_SEL:
982 return objc_write_selector (stream, *(SEL*)data);
983 break;
985 case _C_CHR:
986 return objc_write_char(stream, *(char*)data);
987 break;
989 case _C_UCHR:
990 return objc_write_unsigned_char(stream, *(unsigned char*)data);
991 break;
993 case _C_SHT:
994 return objc_write_short(stream, *(short*)data);
995 break;
997 case _C_USHT:
998 return objc_write_unsigned_short(stream, *(unsigned short*)data);
999 break;
1001 case _C_INT:
1002 return objc_write_int(stream, *(int*)data);
1003 break;
1005 case _C_UINT:
1006 return objc_write_unsigned_int(stream, *(unsigned int*)data);
1007 break;
1009 case _C_LNG:
1010 return objc_write_long(stream, *(long*)data);
1011 break;
1013 case _C_ULNG:
1014 return objc_write_unsigned_long(stream, *(unsigned long*)data);
1015 break;
1017 case _C_CHARPTR:
1018 return objc_write_string (stream, *(char**)data, strlen(*(char**)data));
1019 break;
1021 case _C_ATOM:
1022 return objc_write_string_atomic (stream, *(char**)data, strlen(*(char**)data));
1023 break;
1025 case _C_ARY_B:
1027 int len = atoi(type+1);
1028 while (isdigit(*++type))
1030 return objc_write_array (stream, type, len, data);
1032 break;
1034 case _C_STRUCT_B:
1036 int acc_size = 0;
1037 int align;
1038 while (*type != _C_STRUCT_E && *type++ != '=')
1039 ; /* skip "<name>=" */
1040 while (*type != _C_STRUCT_E)
1042 align = objc_alignof_type (type); /* padd to alignment */
1043 acc_size += ROUND (acc_size, align);
1044 objc_write_type (stream, type, ((char*)data)+acc_size);
1045 acc_size += objc_sizeof_type (type); /* add component size */
1046 type = objc_skip_typespec (type); /* skip component */
1048 return 1;
1051 default:
1052 fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
1053 abort();
1058 ** Read one object, encoded in TYPE and pointed to by DATA to the
1059 ** typed stream STREAM. DATA specifies the address of the types to
1060 ** read. Expected type is checked against the type actually present
1061 ** on the stream.
1065 objc_read_type(TypedStream* stream, const char* type, void* data)
1067 char c;
1068 switch(c = *type) {
1069 case _C_ID:
1070 return objc_read_object (stream, (id*)data);
1071 break;
1073 case _C_CLASS:
1074 return objc_read_class (stream, (Class*)data);
1075 break;
1077 case _C_SEL:
1078 return objc_read_selector (stream, (SEL*)data);
1079 break;
1081 case _C_CHR:
1082 return objc_read_char (stream, (char*)data);
1083 break;
1085 case _C_UCHR:
1086 return objc_read_unsigned_char (stream, (unsigned char*)data);
1087 break;
1089 case _C_SHT:
1090 return objc_read_short (stream, (short*)data);
1091 break;
1093 case _C_USHT:
1094 return objc_read_unsigned_short (stream, (unsigned short*)data);
1095 break;
1097 case _C_INT:
1098 return objc_read_int (stream, (int*)data);
1099 break;
1101 case _C_UINT:
1102 return objc_read_unsigned_int (stream, (unsigned int*)data);
1103 break;
1105 case _C_LNG:
1106 return objc_read_long (stream, (long*)data);
1107 break;
1109 case _C_ULNG:
1110 return objc_read_unsigned_long (stream, (unsigned long*)data);
1111 break;
1113 case _C_CHARPTR:
1114 case _C_ATOM:
1115 return objc_read_string (stream, (char**)data);
1116 break;
1118 case _C_ARY_B:
1120 int len = atoi(type+1);
1121 while (isdigit(*++type))
1123 return objc_read_array (stream, type, len, data);
1125 break;
1127 case _C_STRUCT_B:
1129 int acc_size = 0;
1130 int align;
1131 while (*type != _C_STRUCT_E && *type++ != '=')
1132 ; /* skip "<name>=" */
1133 while (*type != _C_STRUCT_E)
1135 align = objc_alignof_type (type); /* padd to alignment */
1136 acc_size += ROUND (acc_size, align);
1137 objc_read_type (stream, type, ((char*)data)+acc_size);
1138 acc_size += objc_sizeof_type (type); /* add component size */
1139 type = objc_skip_typespec (type); /* skip component */
1141 return 1;
1144 default:
1145 fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
1146 abort();
1151 ** Write the object specified by the template TYPE to STREAM. Last
1152 ** arguments specify addresses of values to be written. It might
1153 ** seem surprising to specify values by address, but this is extremely
1154 ** convenient for copy-paste with objc_read_types calls. A more
1155 ** down-to-the-earth cause for this passing of addresses is that values
1156 ** of arbitrary size is not well supported in ANSI C for functions with
1157 ** variable number of arguments.
1160 int
1161 objc_write_types (TypedStream* stream, const char* type, ...)
1163 va_list args;
1164 const char *c;
1165 int res = 0;
1167 va_start(args, type);
1169 for (c = type; *c; c = objc_skip_typespec (c))
1171 switch(*c) {
1172 case _C_ID:
1173 res = objc_write_object (stream, *va_arg (args, id*));
1174 break;
1176 case _C_CLASS:
1177 res = objc_write_class (stream, *va_arg(args, Class*));
1178 break;
1180 case _C_SEL:
1181 res = objc_write_selector (stream, *va_arg(args, SEL*));
1182 break;
1184 case _C_CHR:
1185 res = objc_write_char (stream, *va_arg (args, char*));
1186 break;
1188 case _C_UCHR:
1189 res = objc_write_unsigned_char (stream,
1190 *va_arg (args, unsigned char*));
1191 break;
1193 case _C_SHT:
1194 res = objc_write_short (stream, *va_arg(args, short*));
1195 break;
1197 case _C_USHT:
1198 res = objc_write_unsigned_short (stream,
1199 *va_arg(args, unsigned short*));
1200 break;
1202 case _C_INT:
1203 res = objc_write_int(stream, *va_arg(args, int*));
1204 break;
1206 case _C_UINT:
1207 res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
1208 break;
1210 case _C_LNG:
1211 res = objc_write_long(stream, *va_arg(args, long*));
1212 break;
1214 case _C_ULNG:
1215 res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*));
1216 break;
1218 case _C_CHARPTR:
1220 char** str = va_arg(args, char**);
1221 res = objc_write_string (stream, *str, strlen(*str));
1223 break;
1225 case _C_ATOM:
1227 char** str = va_arg(args, char**);
1228 res = objc_write_string_atomic (stream, *str, strlen(*str));
1230 break;
1232 case _C_ARY_B:
1234 int len = atoi(c+1);
1235 const char* t = c;
1236 while (isdigit(*++t))
1238 res = objc_write_array (stream, t, len, va_arg(args, void*));
1239 t = objc_skip_typespec (t);
1240 if (*t != _C_ARY_E)
1241 __objc_fatal("expected `]', got: %s", t);
1243 break;
1245 default:
1246 fprintf(stderr, "objc_write_types: cannot parse typespec: %s\n", type);
1247 abort();
1250 va_end(args);
1251 return res;
1256 ** Last arguments specify addresses of values to be read. Expected
1257 ** type is checked against the type actually present on the stream.
1260 int
1261 objc_read_types(TypedStream* stream, const char* type, ...)
1263 va_list args;
1264 const char *c;
1265 int res = 0;
1267 va_start(args, type);
1269 for (c = type; *c; c = objc_skip_typespec(c))
1271 switch(*c) {
1272 case _C_ID:
1273 res = objc_read_object(stream, va_arg(args, id*));
1274 break;
1276 case _C_CLASS:
1277 res = objc_read_class(stream, va_arg(args, Class*));
1278 break;
1280 case _C_SEL:
1281 res = objc_read_selector(stream, va_arg(args, SEL*));
1282 break;
1284 case _C_CHR:
1285 res = objc_read_char(stream, va_arg(args, char*));
1286 break;
1288 case _C_UCHR:
1289 res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
1290 break;
1292 case _C_SHT:
1293 res = objc_read_short(stream, va_arg(args, short*));
1294 break;
1296 case _C_USHT:
1297 res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
1298 break;
1300 case _C_INT:
1301 res = objc_read_int(stream, va_arg(args, int*));
1302 break;
1304 case _C_UINT:
1305 res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
1306 break;
1308 case _C_LNG:
1309 res = objc_read_long(stream, va_arg(args, long*));
1310 break;
1312 case _C_ULNG:
1313 res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*));
1314 break;
1316 case _C_CHARPTR:
1317 case _C_ATOM:
1319 char** str = va_arg(args, char**);
1320 res = objc_read_string (stream, str);
1322 break;
1324 case _C_ARY_B:
1326 int len = atoi(c+1);
1327 const char* t = c;
1328 while (isdigit(*++t))
1330 res = objc_read_array (stream, t, len, va_arg(args, void*));
1331 t = objc_skip_typespec (t);
1332 if (*t != _C_ARY_E)
1333 __objc_fatal("expected `]', got: %s", t);
1335 break;
1337 default:
1338 fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
1339 abort();
1342 va_end(args);
1343 return res;
1347 ** Write an array of COUNT elements of TYPE from the memory address DATA.
1348 ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
1352 objc_write_array (TypedStream* stream, const char* type,
1353 int count, const void* data)
1355 int off = objc_sizeof_type(type);
1356 const char* where = data;
1358 while (count-- > 0)
1360 objc_write_type(stream, type, where);
1361 where += off;
1363 return 1;
1367 ** Read an array of COUNT elements of TYPE into the memory address
1368 ** DATA. The memory pointed to by data is supposed to be allocated
1369 ** by the callee. This is equivalent of
1370 ** objc_read_type (stream, "[N<type>]", data)
1374 objc_read_array (TypedStream* stream, const char* type,
1375 int count, void* data)
1377 int off = objc_sizeof_type(type);
1378 char* where = (char*)data;
1380 while (count-- > 0)
1382 objc_read_type(stream, type, where);
1383 where += off;
1385 return 1;
1388 static void
1389 __objc_free (void* p)
1391 free (p);
1394 static int
1395 __objc_fread(FILE* file, char* data, int len)
1397 return fread(data, len, 1, file);
1400 static int
1401 __objc_fwrite(FILE* file, char* data, int len)
1403 return fwrite(data, len, 1, file);
1406 static int
1407 __objc_feof(FILE* file)
1409 return feof(file);
1412 static int
1413 __objc_no_write(FILE* file, char* data, int len)
1415 __objc_fatal ("TypedStream not open for writing");
1418 static int
1419 __objc_no_read(FILE* file, char* data, int len)
1421 __objc_fatal ("TypedStream not open for reading");
1424 static int
1425 __objc_read_typed_stream_signature (TypedStream* stream)
1427 char buffer[80];
1428 int pos = 0;
1430 (*stream->read)(stream->physical, buffer+pos, 1);
1431 while (buffer[pos++] != '\0')
1433 sscanf (buffer, "GNU TypedStream %d", &stream->version);
1434 if (stream->version != OBJC_TYPED_STREAM_VERSION)
1435 __objc_fatal ("cannot handle TypedStream version %d", stream->version);
1436 return 1;
1439 static int
1440 __objc_write_typed_stream_signature (TypedStream* stream)
1442 char buffer[80];
1443 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
1444 stream->version = OBJC_TYPED_STREAM_VERSION;
1445 (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
1446 return 1;
1449 static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
1451 hash_delete (stream->object_table);
1452 stream->object_table = hash_new(64,
1453 (hash_func_type)hash_ptr,
1454 (compare_func_type)compare_ptrs);
1457 static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
1459 node_ptr node;
1460 struct objc_list* free_list;
1461 SEL awake_sel = sel_get_any_uid ("awake");
1463 /* resolve object forward references */
1464 free_list = list_cons(NULL, NULL);
1465 for (node = hash_next (stream->object_refs, NULL); node;
1466 node = hash_next (stream->object_refs, node))
1468 struct objc_list* reflist = node->value;
1469 const void* key = node->key;
1470 id object = hash_value_for_key (stream->object_table, key);
1471 while(reflist)
1473 *((id*)reflist->head) = object;
1474 if (list_find(&free_list, reflist) == NULL)
1475 free_list = list_cons (reflist, free_list);
1476 reflist = reflist->tail;
1479 list_mapcar (free_list, __objc_free);
1480 list_free (free_list);
1482 /* empty object reference table */
1483 hash_delete (stream->object_refs);
1484 stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1485 (compare_func_type)compare_ptrs);
1487 /* call -awake for all objects read */
1488 if (awake_sel)
1490 for (node = hash_next (stream->object_table, NULL); node;
1491 node = hash_next (stream->object_table, node))
1493 id object = node->value;
1494 if (__objc_responds_to (object, awake_sel))
1495 (*objc_msg_lookup(object, awake_sel))(object, awake_sel);
1499 /* empty object table */
1500 hash_delete (stream->object_table);
1501 stream->object_table = hash_new(64,
1502 (hash_func_type)hash_ptr,
1503 (compare_func_type)compare_ptrs);
1507 ** Open the stream PHYSICAL in MODE
1510 TypedStream*
1511 objc_open_typed_stream (FILE* physical, int mode)
1513 TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
1515 s->mode = mode;
1516 s->physical = physical;
1517 s->stream_table = hash_new(64,
1518 (hash_func_type)hash_ptr,
1519 (compare_func_type)compare_ptrs);
1520 s->object_table = hash_new(64,
1521 (hash_func_type)hash_ptr,
1522 (compare_func_type)compare_ptrs);
1523 s->eof = (objc_typed_eof_func)__objc_feof;
1524 s->flush = (objc_typed_flush_func)fflush;
1525 s->writing_root_p = 0;
1526 if (mode == OBJC_READONLY)
1528 s->class_table = hash_new(8, (hash_func_type)hash_string,
1529 (compare_func_type)compare_strings);
1530 s->object_refs = hash_new(8, (hash_func_type)hash_ptr,
1531 (compare_func_type)compare_ptrs);
1532 s->read = (objc_typed_read_func)__objc_fread;
1533 s->write = (objc_typed_write_func)__objc_no_write;
1534 __objc_read_typed_stream_signature (s);
1536 else if (mode == OBJC_WRITEONLY)
1538 s->class_table = 0;
1539 s->object_refs = 0;
1540 s->read = (objc_typed_read_func)__objc_no_read;
1541 s->write = (objc_typed_write_func)__objc_fwrite;
1542 __objc_write_typed_stream_signature (s);
1544 else
1546 objc_close_typed_stream (s);
1547 return NULL;
1549 s->type = OBJC_FILE_STREAM;
1550 return s;
1554 ** Open the file named by FILE_NAME in MODE
1557 TypedStream*
1558 objc_open_typed_stream_for_file (const char* file_name, int mode)
1560 FILE* file = NULL;
1561 TypedStream* s;
1563 if (mode == OBJC_READONLY)
1564 file = fopen (file_name, "r");
1565 else
1566 file = fopen (file_name, "w");
1568 if (file)
1570 s = objc_open_typed_stream (file, mode);
1571 if (s)
1572 s->type |= OBJC_MANAGED_STREAM;
1573 return s;
1575 else
1576 return NULL;
1580 ** Close STREAM freeing the structure it self. If it was opened with
1581 ** objc_open_typed_stream_for_file, the file will also be closed.
1584 void
1585 objc_close_typed_stream (TypedStream* stream)
1587 if (stream->mode == OBJC_READONLY)
1589 __objc_finish_read_root_object (stream); /* Just in case... */
1590 hash_delete (stream->class_table);
1591 hash_delete (stream->object_refs);
1594 hash_delete (stream->stream_table);
1595 hash_delete (stream->object_table);
1597 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
1598 fclose ((FILE*)stream->physical);
1600 free (stream);
1603 BOOL
1604 objc_end_of_typed_stream (TypedStream* stream)
1606 return (*stream->eof)(stream->physical);
1609 void
1610 objc_flush_typed_stream (TypedStream* stream)
1612 (*stream->flush)(stream->physical);
1615 long
1616 objc_get_stream_class_version (TypedStream* stream, Class class)
1618 if (stream->class_table)
1619 return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
1620 else
1621 return class_get_version (class);