]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/testsuite/objc/execute/next_mapping.h
Cleanup double words.
[thirdparty/gcc.git] / gcc / testsuite / objc / execute / next_mapping.h
1 /* This file "renames" various ObjC GNU runtime entry points
2 (and fakes the existence of several others)
3 if the NeXT runtime is being used. */
4 /* Authors: Ziemowit Laski <zlaski@apple.com> */
5 /* David Ayers <d.ayers@inode.at> */
6
7 #ifdef __NEXT_RUNTIME__
8 #include <objc/objc-class.h>
9 #include <objc/Object.h>
10 #include <ctype.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #define objc_get_class(C) objc_getClass(C)
15 #define objc_get_meta_class(C) objc_getMetaClass(C)
16 #define class_get_class_method(C, S) class_getClassMethod(C, S)
17 #define class_get_instance_method(C, S) class_getInstanceMethod(C, S)
18 #define method_get_imp(M) (((Method)M)->method_imp)
19 #define sel_get_name(S) sel_getName(S)
20 #define class_create_instance(C) class_createInstance(C, 0)
21 #define class_get_class_name(C) object_getClassName(C)
22 #define class_get_super_class(C) (((struct objc_class *)C)->super_class)
23 #define object_get_super_class(O) class_get_super_class(*(struct objc_class **)O)
24 #define objc_lookup_class(N) objc_lookUpClass(N)
25 #define object_get_class(O) (*(struct objc_class **)O)
26 #define class_is_class(C) (CLS_GETINFO((struct objc_class *)C, CLS_CLASS)? YES: NO)
27 #define class_is_meta_class(C) (CLS_GETINFO((struct objc_class *)C, CLS_META)? YES: NO)
28 #define object_is_class(O) class_is_meta_class(*(struct objc_class **)O)
29 #define object_is_meta_class(O) (class_is_meta_class(O) && class_is_meta_class(*(struct objc_class **)O))
30
31 /* You need either an empty +initialize method or an empty -forward:: method.
32 The NeXT runtime unconditionally sends +initialize to classes when they are
33 first used, and unconditionally tries to forward methods that the class
34 doesn't understand (including +initialize). If you have neither +initialize
35 nor -forward::, the runtime complains.
36
37 The simplest workaround is to add
38
39 + initialize { return self; }
40
41 to every root class @implementation. */
42
43 #ifndef NULL
44 #define NULL 0
45 #endif
46
47 /* The following is necessary to "cover" the bf*.m test cases on NeXT. */
48
49 #undef MAX
50 #undef MIN
51 #undef ROUND
52
53 #ifdef __cplusplus
54 #define MAX(X, Y) ((X > Y) ? X : Y)
55 #define MIN(X, Y) ((X < Y) ? X : Y)
56 #define ROUND(V, A) (A * ((V + A - 1) / A))
57 #else
58 #define MAX(X, Y) \
59 ({ typeof (X) __x = (X), __y = (Y); \
60 (__x > __y ? __x : __y); })
61 #define MIN(X, Y) \
62 ({ typeof (X) __x = (X), __y = (Y); \
63 (__x < __y ? __x : __y); })
64 #define ROUND(V, A) \
65 ({ typeof (V) __v = (V); typeof (A) __a = (A); \
66 __a * ((__v+__a - 1)/__a); })
67 #endif
68
69 #define BITS_PER_UNIT __CHAR_BIT__
70 typedef struct{ char a; } __small_struct;
71 #define STRUCTURE_SIZE_BOUNDARY (BITS_PER_UNIT * sizeof (__small_struct))
72
73 /* Not sure why the following are missing from NeXT objc headers... */
74
75 #ifndef _C_LNG_LNG
76 #define _C_LNG_LNG 'q'
77 #endif
78 #ifndef _C_ULNG_LNG
79 #define _C_ULNG_LNG 'Q'
80 #endif
81 #ifndef _C_ATOM
82 #define _C_ATOM '%'
83 #endif
84 #ifndef _C_BOOL
85 #define _C_BOOL 'B'
86 #endif
87
88 #define _C_CONST 'r'
89 #define _C_IN 'n'
90 #define _C_INOUT 'N'
91 #define _C_OUT 'o'
92 #define _C_BYCOPY 'O'
93 #define _C_BYREF 'R'
94 #define _C_ONEWAY 'V'
95 #define _C_GCINVISIBLE '!'
96
97 #define _F_CONST 0x01
98 #define _F_IN 0x01
99 #define _F_OUT 0x02
100 #define _F_INOUT 0x03
101 #define _F_BYCOPY 0x04
102 #define _F_BYREF 0x08
103 #define _F_ONEWAY 0x10
104 #define _F_GCINVISIBLE 0x20
105
106 struct objc_struct_layout
107 {
108 const char *original_type;
109 const char *type;
110 const char *prev_type;
111 unsigned int record_size;
112 unsigned int record_align;
113 };
114
115 typedef union arglist {
116 char *arg_ptr;
117 char arg_regs[sizeof (char*)];
118 } *arglist_t; /* argument frame */
119
120 const char *objc_skip_typespec (const char *type);
121 void objc_layout_structure_get_info (struct objc_struct_layout *layout,
122 unsigned int *offset, unsigned int *align, const char **type);
123 void objc_layout_structure (const char *type,
124 struct objc_struct_layout *layout);
125 BOOL objc_layout_structure_next_member (struct objc_struct_layout *layout);
126 void objc_layout_finish_structure (struct objc_struct_layout *layout,
127 unsigned int *size, unsigned int *align);
128 int objc_aligned_size (const char *type);
129
130 /*
131 return the size of an object specified by type
132 */
133
134 int
135 objc_sizeof_type (const char *type)
136 {
137 /* Skip the variable name if any */
138 if (*type == '"')
139 {
140 for (type++; *type++ != '"';)
141 /* do nothing */;
142 }
143
144 switch (*type) {
145 case _C_ID:
146 return sizeof (id);
147 break;
148
149 case _C_CLASS:
150 return sizeof (Class);
151 break;
152
153 case _C_SEL:
154 return sizeof (SEL);
155 break;
156
157 case _C_CHR:
158 return sizeof (char);
159 break;
160
161 case _C_UCHR:
162 return sizeof (unsigned char);
163 break;
164
165 case _C_SHT:
166 return sizeof (short);
167 break;
168
169 case _C_USHT:
170 return sizeof (unsigned short);
171 break;
172
173 case _C_INT:
174 return sizeof (int);
175 break;
176
177 case _C_UINT:
178 return sizeof (unsigned int);
179 break;
180
181 case _C_LNG:
182 return sizeof (long);
183 break;
184
185 case _C_ULNG:
186 return sizeof (unsigned long);
187 break;
188
189 case _C_LNG_LNG:
190 return sizeof (long long);
191 break;
192
193 case _C_ULNG_LNG:
194 return sizeof (unsigned long long);
195 break;
196
197 case _C_FLT:
198 return sizeof (float);
199 break;
200
201 case _C_DBL:
202 return sizeof (double);
203 break;
204
205 case _C_PTR:
206 case _C_ATOM:
207 case _C_CHARPTR:
208 return sizeof (char *);
209 break;
210
211 case _C_ARY_B:
212 {
213 int len = atoi (type + 1);
214 while (isdigit ((unsigned char)*++type))
215 ;
216 return len * objc_aligned_size (type);
217 }
218 break;
219
220 case _C_BFLD:
221 {
222 /* The NeXT encoding of bitfields is _still_: b 'size' */
223 int size = atoi (type + 1);
224 /* Return an upper bound on byte size */
225 return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
226 }
227
228 case _C_STRUCT_B:
229 {
230 struct objc_struct_layout layout;
231 unsigned int size;
232
233 objc_layout_structure (type, &layout);
234 while (objc_layout_structure_next_member (&layout))
235 /* do nothing */ ;
236 objc_layout_finish_structure (&layout, &size, NULL);
237
238 return size;
239 }
240
241 case _C_UNION_B:
242 {
243 int max_size = 0;
244 while (*type != _C_UNION_E && *type++ != '=')
245 /* do nothing */;
246 while (*type != _C_UNION_E)
247 {
248 /* Skip the variable name if any */
249 if (*type == '"')
250 {
251 for (type++; *type++ != '"';)
252 /* do nothing */;
253 }
254 max_size = MAX (max_size, objc_sizeof_type (type));
255 type = objc_skip_typespec (type);
256 }
257 return max_size;
258 }
259 }
260 return 0; /* error */
261 }
262
263
264 /*
265 Return the alignment of an object specified by type
266 */
267
268 int
269 objc_alignof_type (const char *type)
270 {
271 /* Skip the variable name if any */
272 if (*type == '"')
273 {
274 for (type++; *type++ != '"';)
275 /* do nothing */;
276 }
277 switch (*type) {
278 case _C_ID:
279 return __alignof__ (id);
280 break;
281
282 case _C_CLASS:
283 return __alignof__ (Class);
284 break;
285
286 case _C_SEL:
287 return __alignof__ (SEL);
288 break;
289
290 case _C_CHR:
291 return __alignof__ (char);
292 break;
293
294 case _C_UCHR:
295 return __alignof__ (unsigned char);
296 break;
297
298 case _C_SHT:
299 return __alignof__ (short);
300 break;
301
302 case _C_USHT:
303 return __alignof__ (unsigned short);
304 break;
305
306 case _C_INT:
307 case _C_BFLD: /* This is for the NeXT only */
308 return __alignof__ (int);
309 break;
310
311 case _C_UINT:
312 return __alignof__ (unsigned int);
313 break;
314
315 case _C_LNG:
316 return __alignof__ (long);
317 break;
318
319 case _C_ULNG:
320 return __alignof__ (unsigned long);
321 break;
322
323 case _C_LNG_LNG:
324 return __alignof__ (long long);
325 break;
326
327 case _C_ULNG_LNG:
328 return __alignof__ (unsigned long long);
329 break;
330
331 case _C_FLT:
332 return __alignof__ (float);
333 break;
334
335 case _C_DBL:
336 return __alignof__ (double);
337 break;
338
339 case _C_PTR:
340 case _C_ATOM:
341 case _C_CHARPTR:
342 return __alignof__ (char *);
343 break;
344
345 case _C_ARY_B:
346 while (isdigit ((unsigned char)*++type))
347 /* do nothing */;
348 return objc_alignof_type (type);
349
350 case _C_STRUCT_B:
351 {
352 struct objc_struct_layout layout;
353 unsigned int align;
354
355 objc_layout_structure (type, &layout);
356 while (objc_layout_structure_next_member (&layout))
357 /* do nothing */;
358 objc_layout_finish_structure (&layout, NULL, &align);
359
360 return align;
361 }
362
363 case _C_UNION_B:
364 {
365 int maxalign = 0;
366 while (*type != _C_UNION_E && *type++ != '=')
367 /* do nothing */;
368 while (*type != _C_UNION_E)
369 {
370 /* Skip the variable name if any */
371 if (*type == '"')
372 {
373 for (type++; *type++ != '"';)
374 /* do nothing */;
375 }
376 maxalign = MAX (maxalign, objc_alignof_type (type));
377 type = objc_skip_typespec (type);
378 }
379 return maxalign;
380 }
381 }
382 return 0; /* error */
383 }
384
385 /*
386 The aligned size if the size rounded up to the nearest alignment.
387 */
388
389 int
390 objc_aligned_size (const char *type)
391 {
392 int size, align;
393
394 /* Skip the variable name */
395 if (*type == '"')
396 {
397 for (type++; *type++ != '"';)
398 /* do nothing */;
399 }
400
401 size = objc_sizeof_type (type);
402 align = objc_alignof_type (type);
403
404 return ROUND (size, align);
405 }
406
407 /*
408 The size rounded up to the nearest integral of the wordsize, taken
409 to be the size of a void *.
410 */
411
412 int
413 objc_promoted_size (const char *type)
414 {
415 int size, wordsize;
416
417 /* Skip the variable name */
418 if (*type == '"')
419 {
420 for (type++; *type++ != '"';)
421 /* do nothing */;
422 }
423
424 size = objc_sizeof_type (type);
425 wordsize = sizeof (void *);
426
427 return ROUND (size, wordsize);
428 }
429
430 /*
431 Skip type qualifiers. These may eventually precede typespecs
432 occurring in method prototype encodings.
433 */
434
435 inline const char *
436 objc_skip_type_qualifiers (const char *type)
437 {
438 while (*type == _C_CONST
439 || *type == _C_IN
440 || *type == _C_INOUT
441 || *type == _C_OUT
442 || *type == _C_BYCOPY
443 || *type == _C_BYREF
444 || *type == _C_ONEWAY
445 || *type == _C_GCINVISIBLE)
446 {
447 type += 1;
448 }
449 return type;
450 }
451
452
453 /*
454 Skip one typespec element. If the typespec is prepended by type
455 qualifiers, these are skipped as well.
456 */
457
458 const char *
459 objc_skip_typespec (const char *type)
460 {
461 /* Skip the variable name if any */
462 if (*type == '"')
463 {
464 for (type++; *type++ != '"';)
465 /* do nothing */;
466 }
467
468 type = objc_skip_type_qualifiers (type);
469
470 switch (*type) {
471
472 case _C_ID:
473 /* An id may be annotated by the actual type if it is known
474 with the @"ClassName" syntax */
475
476 if (*++type != '"')
477 return type;
478 else
479 {
480 while (*++type != '"')
481 /* do nothing */;
482 return type + 1;
483 }
484
485 /* The following are one character type codes */
486 case _C_CLASS:
487 case _C_SEL:
488 case _C_CHR:
489 case _C_UCHR:
490 case _C_CHARPTR:
491 case _C_ATOM:
492 case _C_SHT:
493 case _C_USHT:
494 case _C_INT:
495 case _C_UINT:
496 case _C_LNG:
497 case _C_ULNG:
498 case _C_LNG_LNG:
499 case _C_ULNG_LNG:
500 case _C_FLT:
501 case _C_DBL:
502 case _C_VOID:
503 case _C_UNDEF:
504 return ++type;
505 break;
506
507 case _C_ARY_B:
508 /* skip digits, typespec and closing ']' */
509
510 while (isdigit ((unsigned char)*++type))
511 ;
512 type = objc_skip_typespec (type);
513 if (*type == _C_ARY_E)
514 return ++type;
515 else
516 break; /* error */
517
518 case _C_BFLD:
519 /* The NeXT encoding for bitfields is _still_: b 'size' */
520 while (isdigit ((unsigned char)*++type))
521 ; /* skip type and size */
522 return type;
523
524 case _C_STRUCT_B:
525 /* skip name, and elements until closing '}' */
526
527 while (*type != _C_STRUCT_E && *type++ != '=')
528 ;
529 while (*type != _C_STRUCT_E)
530 {
531 type = objc_skip_typespec (type);
532 }
533 return ++type;
534
535 case _C_UNION_B:
536 /* skip name, and elements until closing ')' */
537
538 while (*type != _C_UNION_E && *type++ != '=')
539 ;
540 while (*type != _C_UNION_E)
541 {
542 type = objc_skip_typespec (type);
543 }
544 return ++type;
545
546 case _C_PTR:
547 /* Just skip the following typespec */
548
549 return objc_skip_typespec (++type);
550 }
551 return 0; /* error */
552 }
553
554 /*
555 Skip an offset as part of a method encoding. This is prepended by a
556 '+' if the argument is passed in registers.
557 */
558 inline const char *
559 objc_skip_offset (const char *type)
560 {
561 if (*type == '+')
562 type++;
563 while (isdigit ((unsigned char) *++type))
564 ;
565 return type;
566 }
567
568 /*
569 Skip an argument specification of a method encoding.
570 */
571 const char *
572 objc_skip_argspec (const char *type)
573 {
574 type = objc_skip_typespec (type);
575 type = objc_skip_offset (type);
576 return type;
577 }
578
579 /*
580 Return the number of arguments that the method MTH expects.
581 Note that all methods need two implicit arguments `self' and
582 `_cmd'.
583 */
584 int
585 method_get_number_of_arguments (struct objc_method *mth)
586 {
587 int i = 0;
588 const char *type = mth->method_types;
589 while (*type)
590 {
591 type = objc_skip_argspec (type);
592 i += 1;
593 }
594 return i - 1;
595 }
596
597 /*
598 Return the size of the argument block needed on the stack to invoke
599 the method MTH. This may be zero, if all arguments are passed in
600 registers.
601 */
602
603 int
604 method_get_sizeof_arguments (struct objc_method *mth)
605 {
606 const char *type = objc_skip_typespec (mth->method_types);
607 return atoi (type);
608 }
609
610 /*
611 Return a pointer to the next argument of ARGFRAME. type points to
612 the last argument. Typical use of this look like:
613
614 {
615 char *datum, *type;
616 for (datum = method_get_first_argument (method, argframe, &type);
617 datum; datum = method_get_next_argument (argframe, &type))
618 {
619 unsigned flags = objc_get_type_qualifiers (type);
620 type = objc_skip_type_qualifiers (type);
621 if (*type != _C_PTR)
622 [portal encodeData: datum ofType: type];
623 else
624 {
625 if ((flags & _F_IN) == _F_IN)
626 [portal encodeData: *(char **) datum ofType: ++type];
627 }
628 }
629 }
630 */
631
632 char *
633 method_get_next_argument (arglist_t argframe, const char **type)
634 {
635 const char *t = objc_skip_argspec (*type);
636
637 if (*t == '\0')
638 return 0;
639
640 *type = t;
641 t = objc_skip_typespec (t);
642
643 if (*t == '+')
644 return argframe->arg_regs + atoi (++t);
645 else
646 return argframe->arg_ptr + atoi (t);
647 }
648
649 /*
650 Return a pointer to the value of the first argument of the method
651 described in M with the given argumentframe ARGFRAME. The type
652 is returned in TYPE. type must be passed to successive calls of
653 method_get_next_argument.
654 */
655 char *
656 method_get_first_argument (struct objc_method *m,
657 arglist_t argframe,
658 const char **type)
659 {
660 *type = m->method_types;
661 return method_get_next_argument (argframe, type);
662 }
663
664 /*
665 Return a pointer to the ARGth argument of the method
666 M from the frame ARGFRAME. The type of the argument
667 is returned in the value-result argument TYPE
668 */
669
670 char *
671 method_get_nth_argument (struct objc_method *m,
672 arglist_t argframe, int arg,
673 const char **type)
674 {
675 const char *t = objc_skip_argspec (m->method_types);
676
677 if (arg > method_get_number_of_arguments (m))
678 return 0;
679
680 while (arg--)
681 t = objc_skip_argspec (t);
682
683 *type = t;
684 t = objc_skip_typespec (t);
685
686 if (*t == '+')
687 return argframe->arg_regs + atoi (++t);
688 else
689 return argframe->arg_ptr + atoi (t);
690 }
691
692 unsigned
693 objc_get_type_qualifiers (const char *type)
694 {
695 unsigned res = 0;
696 BOOL flag = YES;
697
698 while (flag)
699 switch (*type++)
700 {
701 case _C_CONST: res |= _F_CONST; break;
702 case _C_IN: res |= _F_IN; break;
703 case _C_INOUT: res |= _F_INOUT; break;
704 case _C_OUT: res |= _F_OUT; break;
705 case _C_BYCOPY: res |= _F_BYCOPY; break;
706 case _C_BYREF: res |= _F_BYREF; break;
707 case _C_ONEWAY: res |= _F_ONEWAY; break;
708 case _C_GCINVISIBLE: res |= _F_GCINVISIBLE; break;
709 default: flag = NO;
710 }
711
712 return res;
713 }
714
715
716 /* The following three functions can be used to determine how a
717 structure is laid out by the compiler. For example:
718
719 struct objc_struct_layout layout;
720 int i;
721
722 objc_layout_structure (type, &layout);
723 while (objc_layout_structure_next_member (&layout))
724 {
725 int position, align;
726 const char *type;
727
728 objc_layout_structure_get_info (&layout, &position, &align, &type);
729 printf ("element %d has offset %d, alignment %d\n",
730 i++, position, align);
731 }
732
733 These functions are used by objc_sizeof_type and objc_alignof_type
734 functions to compute the size and alignment of structures. The
735 previous method of computing the size and alignment of a structure
736 was not working on some architectures, particulary on AIX, and in
737 the presence of bitfields inside the structure. */
738 void
739 objc_layout_structure (const char *type,
740 struct objc_struct_layout *layout)
741 {
742 const char *ntype;
743
744 layout->original_type = ++type;
745
746 /* Skip "<name>=" if any. Avoid embedded structures and unions. */
747 ntype = type;
748 while (*ntype != _C_STRUCT_E && *ntype != _C_STRUCT_B && *ntype != _C_UNION_B
749 && *ntype++ != '=')
750 /* do nothing */;
751
752 /* If there's a "<name>=", ntype - 1 points to '='; skip the name */
753 if (*(ntype - 1) == '=')
754 type = ntype;
755
756 layout->type = type;
757 layout->prev_type = NULL;
758 layout->record_size = 0;
759 layout->record_align = MAX (BITS_PER_UNIT, STRUCTURE_SIZE_BOUNDARY);
760 }
761
762
763 BOOL
764 objc_layout_structure_next_member (struct objc_struct_layout *layout)
765 {
766 register int desired_align = 0;
767
768 /* The current type without the type qualifiers */
769 const char *type;
770
771 /* Add the size of the previous field to the size of the record. */
772 if (layout->prev_type)
773 {
774 type = objc_skip_type_qualifiers (layout->prev_type);
775
776 if (*type != _C_BFLD)
777 layout->record_size += objc_sizeof_type (type) * BITS_PER_UNIT;
778 else
779 layout->record_size += atoi (++type);
780 }
781
782 if (*layout->type == _C_STRUCT_E)
783 return NO;
784
785 /* Skip the variable name if any */
786 if (*layout->type == '"')
787 {
788 for (layout->type++; *layout->type++ != '"';)
789 /* do nothing */;
790 }
791
792 type = objc_skip_type_qualifiers (layout->type);
793
794 desired_align = objc_alignof_type (type) * BITS_PER_UNIT;
795
796 /* Record must have at least as much alignment as any field.
797 Otherwise, the alignment of the field within the record
798 is meaningless. */
799 layout->record_align = MAX (layout->record_align, desired_align);
800
801 if (*type == _C_BFLD)
802 {
803 int bfld_size = atoi (++type);
804 int int_align = __alignof__ (int) * BITS_PER_UNIT;
805 /* If this bitfield would traverse a word alignment boundary, push it out
806 to that boundary instead. */
807 if (layout->record_size % int_align
808 && (layout->record_size / int_align
809 < (layout->record_size + bfld_size - 1) / int_align))
810 layout->record_size = ROUND (layout->record_size, int_align);
811 }
812 else if (layout->record_size % desired_align != 0)
813 {
814 /* We need to skip space before this field.
815 Bump the cumulative size to multiple of field alignment. */
816 layout->record_size = ROUND (layout->record_size, desired_align);
817 }
818
819 /* Jump to the next field in record. */
820
821 layout->prev_type = layout->type;
822 layout->type = objc_skip_typespec (layout->type); /* skip component */
823
824 return YES;
825 }
826
827
828 void objc_layout_finish_structure (struct objc_struct_layout *layout,
829 unsigned int *size,
830 unsigned int *align)
831 {
832 if (layout->type && *layout->type == _C_STRUCT_E)
833 {
834 /* Round the size up to be a multiple of the required alignment */
835 layout->record_size = ROUND (layout->record_size, layout->record_align);
836 layout->type = NULL;
837 }
838 if (size)
839 *size = layout->record_size / BITS_PER_UNIT;
840 if (align)
841 *align = layout->record_align / BITS_PER_UNIT;
842 }
843
844
845 void objc_layout_structure_get_info (struct objc_struct_layout *layout,
846 unsigned int *offset,
847 unsigned int *align,
848 const char **type)
849 {
850 if (offset)
851 *offset = layout->record_size / BITS_PER_UNIT;
852 if (align)
853 *align = layout->record_align / BITS_PER_UNIT;
854 if (type)
855 *type = layout->prev_type;
856 }
857
858 /* A small, portable NSConstantString implementation for use with the NeXT
859 runtime.
860
861 On full-fledged Mac OS X systems, NSConstantString is provided
862 as part of the Foundation framework. However, on bare Darwin systems,
863 Foundation is not included, and hence there is no NSConstantString
864 implementation to link against.
865
866 This code is derived from the GNU runtime's NXConstantString implementation.
867 */
868
869 struct objc_class _NSConstantStringClassReference;
870
871 @interface NSConstantString : Object
872 {
873 char *c_string;
874 unsigned int len;
875 }
876
877 -(const char *) cString;
878 -(unsigned int) length;
879
880 @end
881
882 @implementation NSConstantString
883
884 -(const char *) cString
885 {
886 return (c_string);
887 }
888
889 -(unsigned int) length
890 {
891 return (len);
892 }
893
894 @end
895
896 /* The NSConstantString metaclass will need to be initialized before we can
897 send messages to strings. */
898
899 void objc_constant_string_init (void) __attribute__((constructor));
900 void objc_constant_string_init (void) {
901 memcpy (&_NSConstantStringClassReference,
902 objc_getClass ("NSConstantString"),
903 sizeof (_NSConstantStringClassReference));
904 }
905
906 #endif /* #ifdef __NEXT_RUNTIME__ */