diff --git a/ChangeLog b/ChangeLog index 6d0c1084b..af6ee071f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-07-03 Ibadinov Marat + + * Source/Additions/GNUmakefile: + * Headers/GNUstepBase/GSTypeEncoding.c: + * Headers/GNUstepBase/GSTypeEncoding.h: + New type encoding parser. + 2013-07-03 Richard Frith-Macdonald * Headers/Foundation/NSException.h: diff --git a/Headers/GNUstepBase/GSTypeEncoding.h b/Headers/GNUstepBase/GSTypeEncoding.h new file mode 100644 index 000000000..e3fe9d0f0 --- /dev/null +++ b/Headers/GNUstepBase/GSTypeEncoding.h @@ -0,0 +1,226 @@ +/* + * Objective-C type encoding support + * + * Copyright (C) 2012-2013 Free Software Foundation, Inc. + * + * Written by Marat Ibadinov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GS_TYPE_ENCODING_H +#define GS_TYPE_ENCODING_H + +#include + +#if defined (NeXT_RUNTIME) +# include +#else +# if defined (__GNU_LIBOBJC__) +# include +# else +# include +# include +# endif +#endif + +#if !defined(ENCODING_INLINE) +# if defined(__GNUC__) +# define ENCODING_INLINE static __inline__ __attribute__((always_inline)) +# elif +# define ENCODING_INLINE static inline +# endif +#endif + +/* type mangling is compiler independent so we can safely define this by hand */ + +typedef enum GSObjCTypeQualifier +{ + GSObjCQualifierConst = 'r', + GSObjCQualifierIn = 'n', + GSObjCQualifierInOut = 'N', + GSObjCQualifierOut = 'o', + GSObjCQualifierByCopy = 'O', + GSObjCQualifierByRef = 'R', + GSObjCQualifierOneWay = 'V', + GSObjCQualifierInvisible = '!' +} GSObjCTypeQualifier; + +typedef enum GSObjCType +{ + GSObjCTypeId = '@', + GSObjCTypeClass = '#', + GSObjCTypeSelector = ':', + GSObjCTypeChar = 'c', + GSObjCTypeUnsignedChar = 'C', + GSObjCTypeShort = 's', + GSObjCTypeUnsignedShort = 'S', + GSObjCTypeInt = 'i', + GSObjCTypeUnsignedInt = 'I', + GSObjCTypeLong = 'l', + GSObjCTypeUnsignedLong = 'L', + GSObjCTypeLongLong = 'q', + GSObjCTypeUnsignedLongLong = 'Q', + GSObjCTypeFloat = 'f', + GSObjCTypeDouble = 'd', + GSObjCTypeComplex = 'j', + GSObjCTypeBitField = 'b', + GSObjCTypeBool = 'B', + GSObjCTypeVoid = 'v', + GSObjCTypePointer = '^', + GSObjCTypeCharPointer = '*', + GSObjCTypeAtom = '%', + GSObjCTypeArrayBegin = '[', + GSObjCTypeArrayEnd = ']', + GSObjCTypeStructureBegin = '{', + GSObjCTypeStructureEnd = '}', + GSObjCTypeUnionBegin = '(', + GSObjCTypeUnionEnd = ')', + GSObjCTypeUnknown = '?' +} GSObjCType; + +/* maximum an minimum char values in a type specification */ +typedef enum GSObjCTypeBound +{ + GSObjCTypeMin = ' ', + GSObjCTypeMax = '~' +} GSObjCTypeBound; + +#if defined (NeXT_RUNTIME) +typedef enum GSObjCTypeQualifierMask +{ + GSObjCQualifierConstMask = 0x01, + GSObjCQualifierInMask = 0x01, + GSObjCQualifierOutMask = 0x02, + GSObjCQualifierInOutMask = 0x03, + GSObjCQualifierByCopyMask = 0x04, + GSObjCQualifierByRefMask = 0x08, + GSObjCQualifierOneWayMask = 0x10, + GSObjCQualifierInvisibleMask = 0x20 +} GSObjCTypeQualifierMask; +#else +typedef enum GSObjCTypeQualifierMask +{ + GSObjCQualifierConstMask = _F_CONST, + GSObjCQualifierInMask = _F_IN, + GSObjCQualifierOutMask = _F_OUT, + GSObjCQualifierInOutMask = _F_INOUT, + GSObjCQualifierByCopyMask = _F_BYCOPY, + GSObjCQualifierByRefMask = _F_BYREF, + GSObjCQualifierOneWayMask = _F_ONEWAY, + GSObjCQualifierInvisibleMask = _F_GCINVISIBLE +} GSObjCTypeQualifierMask; +#endif + +/* + * parser-related stuff + */ + +typedef struct GSObjCTypeInfo { + /* store pointer to allow recursive parsing of pointer types, e.g. ^{^[2*]} */ + const char *type; + size_t size; + uint8_t alignment; + uint8_t qualifiers; +} GSObjCTypeInfo; + +typedef void (*GSObjCTypeParserDelegate)(void *context, GSObjCTypeInfo type); + +typedef enum GSObjCParserOptions { + GSObjCReportArrayOnceMask = 1 +} GSObjCParserOptions; + +const char * +GSObjCParseTypeSpecification (const char *cursor, + GSObjCTypeParserDelegate delegate, + void *context, + unsigned options); + +ENCODING_INLINE size_t +GSObjCPadSize (size_t size, uint8_t alignment) +{ + return alignment * ((size + alignment - 1) / alignment); +} + +ENCODING_INLINE size_t +GSObjCGetPadding (size_t size, uint8_t alignment) +{ + return (alignment - (size & (alignment - 1))) & (alignment - 1); +} + +const char * +GSGetSizeAndAlignment (const char *type, size_t *sizep, uint8_t *alignp); + + +#if defined (NeXT_RUNTIME) + +/* GNU API support for NeXT runtime */ + +int +objc_sizeof_type (const char* type); +int +objc_alignof_type (const char* type); +int +objc_aligned_size (const char* type); +int +objc_promoted_size (const char* type); + +unsigned +objc_get_type_qualifiers (const char* type); + +const char * +objc_skip_typespec (const char* type); +const char * +objc_skip_offset (const char* type); +const char * +objc_skip_argspec (const char* type); +const char * +objc_skip_type_qualifiers (const char* type); + +struct objc_struct_layout +{ + GSObjCTypeInfo *info; + long position; + unsigned count; + unsigned allocated; + unsigned depth; + unsigned offset; + unsigned alignment; +}; + +void +objc_layout_structure (const char *type, + struct objc_struct_layout *layout); + +BOOL +objc_layout_structure_next_member (struct objc_struct_layout *layout); + +void +objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type); + +void +objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align); + +#endif /* NeXT_RUNTIME */ +#endif /* GS_TYPE_ENCODING_H */ diff --git a/Source/Additions/GNUmakefile b/Source/Additions/GNUmakefile index dc0062d61..10103ee2a 100644 --- a/Source/Additions/GNUmakefile +++ b/Source/Additions/GNUmakefile @@ -31,6 +31,9 @@ include ../../config.mak SUBPROJECT_NAME = Additions +Additions_C_FILES =\ + GSTypeEncoding.c \ + Additions_OBJC_FILES =\ GSObjCRuntime.m \ GCObject.m \ @@ -61,7 +64,6 @@ Additions_OBJC_FILES =\ NSThread+GNUstepBase.m \ NSURL+GNUstepBase.m \ - Additions_OBJC_FILES += Unicode.m -include Makefile.preamble diff --git a/Source/Additions/GSTypeEncoding.c b/Source/Additions/GSTypeEncoding.c new file mode 100644 index 000000000..c50dea331 --- /dev/null +++ b/Source/Additions/GSTypeEncoding.c @@ -0,0 +1,729 @@ +/* + * Objective-C type encoding support + * + * Copyright (C) 2012-2013 Free Software Foundation, Inc. + * + * Written by Marat Ibadinov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include "GNUstepBase/GSTypeEncoding.h" + +#undef MAX +#define MAX(X, Y) \ +({ \ + typeof (X) __x = (X), __y = (Y); \ + (__x > __y ? __x : __y); \ +}) + +/* + * We store here aligned sizes of primitive types + * and bit-masks of type qualifiers + */ +static const int8_t typeInfoTable[] = +{ + /* types */ + [GSObjCTypeId] = sizeof(id), + [GSObjCTypeClass] = sizeof(Class), + [GSObjCTypeSelector] = sizeof(SEL), + [GSObjCTypeChar] = sizeof(char), + [GSObjCTypeUnsignedChar] = sizeof(unsigned char), + [GSObjCTypeShort] = sizeof(short), + [GSObjCTypeUnsignedShort] = sizeof(unsigned short), + [GSObjCTypeInt] = sizeof(int), + [GSObjCTypeUnsignedInt] = sizeof(unsigned int), + [GSObjCTypeLong] = sizeof(long), + [GSObjCTypeUnsignedLong] = sizeof(unsigned long), + [GSObjCTypeLongLong] = sizeof(long long), + [GSObjCTypeUnsignedLongLong] = sizeof(unsigned long long), + [GSObjCTypeFloat] = sizeof(float), + [GSObjCTypeDouble] = sizeof(double), + [GSObjCTypeBool] = sizeof(_Bool), + [GSObjCTypeVoid] = sizeof(void), + /* here would go Pointer, but in most cases it needs special treatment */ + [GSObjCTypeCharPointer] = sizeof(char *), + [GSObjCTypeAtom] = sizeof(void *), + /* type qualifiers (negated for distinctiveness) */ + [GSObjCQualifierConst] = -GSObjCQualifierConstMask, + [GSObjCQualifierIn] = -GSObjCQualifierInMask, + [GSObjCQualifierInOut] = -GSObjCQualifierInOutMask, + [GSObjCQualifierOut] = -GSObjCQualifierOutMask, + [GSObjCQualifierByCopy] = -GSObjCQualifierByCopyMask, + [GSObjCQualifierByRef] = -GSObjCQualifierByRefMask, + [GSObjCQualifierOneWay] = -GSObjCQualifierOneWayMask, + [GSObjCQualifierInvisible] = -GSObjCQualifierInvisible, + /* ensure an appropriate table size */ + [GSObjCTypeMax] = 0 +}; + +/* all substripts of typeInfoTable are of char type */ +#ifdef __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wchar-subscripts" +#endif + +ENCODING_INLINE uint8_t +RoundToThePowerOfTwo (uint8_t value) +{ + --value; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + return ++value; +} + +ENCODING_INLINE const char * +GetNumericValue (const char *cursor, int *value) +{ + *value = 0; + while (*cursor >= '0' && *cursor <= '9') + { + *value = 10 * (*value) + (*cursor++ - '0'); + } + return cursor; +} + +ENCODING_INLINE const char * +SkipName (const char *cursor) +{ + if (*cursor == '"') + { + for (++cursor; *cursor++ != '"';); + } + return cursor; +} + +ENCODING_INLINE const char * +SkipType (const char *cursor) +{ + unsigned depth = 0; + do { + while (typeInfoTable[(int)*cursor] < 0) + { + ++cursor; + } + + if (!typeInfoTable[(int)*cursor]) + { + switch (*cursor) + { + case GSObjCTypeArrayBegin: + case GSObjCTypeStructureBegin: + case GSObjCTypeUnionBegin: + ++depth; + break; + case GSObjCTypeArrayEnd: + case GSObjCTypeStructureEnd: + case GSObjCTypeUnionEnd: + --depth; + break; + case GSObjCTypePointer: + ++cursor; + default: + break; + } + } + cursor = SkipName(++cursor); + } while (depth); + return cursor; +} + +ENCODING_INLINE const char * +GetQualifiers (const char *cursor, uint8_t *qualifiers) +{ + *qualifiers = 0; + while (typeInfoTable[(int)*cursor] < 0) + { + *qualifiers |= (uint8_t) -typeInfoTable[(int)*cursor]; + ++cursor; + } + return cursor; +} + +typedef struct ParserStackElement +{ + const char *cursor; + size_t size; + size_t count; /* for arrays */ + char alignment; + char qualifiers; +} ParserStackElement; + + +typedef struct ParserOutput +{ + GSObjCTypeInfo info; + unsigned parentDepth; + BOOL suppressed; +} ParserOutput; + +typedef struct ParserState +{ + ParserStackElement *stack; + ParserOutput *buffer; + unsigned stackSize; + unsigned bufferSize; + unsigned allocated; + unsigned stackSpace; + unsigned bufferSpace; +} ParserState; + +/** + * Complex type nesting level of 4 or greater is a rare case. + * With initial size of 3 total memory footprint of stack and + * buffer is 224 bytes (on machines with 64-bit word). + * + * Nesting depth of 16 will require circa 1K of memory, 64 - approximately 4K. + * Maybe it would be better to place an upper bound on nesting depth and simply + * allocate space on stack once. This will certainly be a performance again. + */ +static const unsigned ParserInitialStackSize = 3; + +ENCODING_INLINE ParserStackElement * +ParserStackTop (ParserState *state) +{ + return state->stackSize ? &state->stack[state->stackSize - 1] : NULL; +} + +const char * +GSObjCParseTypeSpecification (const char *cursor, + GSObjCTypeParserDelegate delegate, + void *context, + unsigned options) +{ + ParserState state; + unsigned suppressionDepth = 0; + unsigned bitFieldSpaceAvailable = 0; + ParserStackElement el; + unsigned index; + + state.stackSize = state.bufferSize = 0; + state.stackSpace = sizeof(ParserStackElement) * ParserInitialStackSize; + state.bufferSpace = sizeof(ParserOutput) * (ParserInitialStackSize + 1); + state.stack = malloc(state.stackSpace + state.bufferSpace); + state.buffer = (void *)state.stack + state.stackSpace; + state.allocated = ParserInitialStackSize; + + do { + GSObjCTypeInfo info = {cursor, 0, 1, 0}; + BOOL pushStack = NO; + BOOL popStack = NO; + BOOL pushBuffer = YES; + BOOL suppress = suppressionDepth != 0; + unsigned parentDepth; + + cursor = GetQualifiers(cursor, &info.qualifiers); + cursor = SkipName(cursor); + parentDepth = state.stackSize; + + /* is it a primitive type? */ + if (typeInfoTable[(int)*cursor]) + { + info.size = info.alignment = typeInfoTable[(int)*cursor]; + cursor = SkipName(++cursor); + } + else + { + switch (*cursor) { + case GSObjCTypeBitField: + { + int totalBitCount = -bitFieldSpaceAvailable; + int bitCount = 0; + + info.alignment = 1; + while (totalBitCount < 8 && *cursor == GSObjCTypeBitField) + /* can we emit token */ + { + cursor = GetNumericValue(++cursor, &bitCount); + totalBitCount += bitCount; + /* round bitCount to the nearest power of 2 */ + info.alignment + = MAX(info.alignment, RoundToThePowerOfTwo(bitCount) / 8); + } + info.size = totalBitCount / 8 + + ((totalBitCount & 7 /* mod 8 */) != 0); + if (*cursor == GSObjCTypeBitField) + { + bitFieldSpaceAvailable + = (unsigned)info.alignment * 8 - totalBitCount; + } + else + bitFieldSpaceAvailable = 0; + break; + } + case GSObjCTypePointer: + { + info.size = info.alignment = sizeof(void *); + cursor = SkipType(++cursor); + break; + } + case GSObjCTypeComplex: + { + info.size = 2 * (info.alignment = typeInfoTable[(int)*++cursor]); + ++cursor; + break; + } + case GSObjCTypeArrayBegin: + { + int length; + + cursor = GetNumericValue(++cursor, &length); + el = (ParserStackElement){ + cursor, 0, length - 1, 1, info.qualifiers + }; + pushStack = YES; + suppressionDepth += (options & GSObjCReportArrayOnceMask) != 0; + break; + } + case GSObjCTypeStructureBegin: + { + el = (ParserStackElement){cursor, 0, 0, 1, info.qualifiers}; + /* skip typename annotation */ + while (*cursor != GSObjCTypeStructureEnd && *cursor++ != '='); + pushStack = YES; + break; + } + case GSObjCTypeUnionBegin: + { + el = (ParserStackElement){cursor, 0, 0, 1, info.qualifiers}; + /* skip typename annotation */ + while (*cursor != GSObjCTypeUnionEnd && *cursor++ != '='); + ++suppressionDepth; + pushStack = YES; + break; + } + case GSObjCTypeUnionEnd: + case GSObjCTypeArrayEnd: + case GSObjCTypeStructureEnd: + { + popStack = YES; + break; + } + + default: + abort(); + } + } + + if (pushStack) + { + if (state.stackSize == state.allocated) + { + unsigned stackSpace; + unsigned bufferSpace; + void *data; + + state.allocated *= 2; + stackSpace = sizeof(ParserStackElement) * state.allocated; + bufferSpace = sizeof(ParserOutput) * (state.allocated + 1); + data = malloc(stackSpace + bufferSpace); + memcpy(data, state.stack, state.stackSpace); + memcpy(data + stackSpace, state.buffer, state.bufferSpace); + free(state.stack); + state.stack = data; + state.buffer = (void *)data + stackSpace; + state.stackSpace = stackSpace; + state.bufferSpace = bufferSpace; + } + state.stack[state.stackSize] = el; + ++state.stackSize; + } + else + { + /* we can safely flush the buffer */ + for (index = 0; index < state.bufferSize; ++index) + { + GSObjCTypeInfo output = state.buffer[index].info; + unsigned depth = state.buffer[index].parentDepth; + + if (depth) + { + ParserStackElement *parent = &state.stack[depth - 1]; + + if (*parent->cursor != GSObjCTypeUnionBegin) + { + size_t alignedSize; + + /* in array and structure we should align data according + * to the element that triggered flushing (it may be the + * next real member of the data-structure or a closing + * tag) + */ + output.alignment = MAX(output.alignment, info.alignment); + alignedSize = GSObjCPadSize(output.size, output.alignment); + parent->size += alignedSize; + } + else + { + parent->size = MAX(parent->size, output.size); + } + parent->alignment = MAX(parent->alignment, output.alignment); + } + if (!state.buffer[index].suppressed) + { + delegate(context, output); + } + } + state.bufferSize = 0; + } + + if (popStack) + { + ParserStackElement *element = ParserStackTop(&state); + + switch (*cursor) + { + case GSObjCTypeUnionEnd: + --suppressionDepth; + case GSObjCTypeArrayEnd: + { + if (element->count) + { + if (options & GSObjCReportArrayOnceMask) + { + /* we need to compensate "length - 1" */ + element->size *= (element->count + 1); + --suppressionDepth; + } + else + { + /* decrease length and rewind */ + --element->count; + cursor = element->cursor; + pushBuffer = NO; + break; + } + } + } + case GSObjCTypeStructureEnd: + { + info.qualifiers = element->qualifiers; + info.size = element->size; + info.alignment = element->alignment; + parentDepth = --state.stackSize; + ++cursor; + break; + } + } + } + + if (pushBuffer) + { + /* outermost GSObjCTypeUnionBegin and GSObjCTypeUnionEnd + * should be reported + */ + state.buffer[state.bufferSize].suppressed + = suppress && suppressionDepth != 0; + state.buffer[state.bufferSize].parentDepth = parentDepth; + state.buffer[state.bufferSize].info = info; + ++state.bufferSize; + } + } while (state.stackSize); + + for (index = 0; index < state.bufferSize; ++index) + { + if (!state.buffer[index].suppressed) + { + delegate(context, state.buffer[index].info); + } + } + + free(state.stack); + + return cursor; +} + +#ifdef __clang__ +#pragma GCC diagnostic pop +#endif + +typedef struct InfoAccumulator +{ + size_t size; + char alignment; +} InfoAccumulator; + +static void +InfoAccumulatorAddInfo (InfoAccumulator *this, GSObjCTypeInfo info) +{ + /* if it's the end of structure, accumulate only padding */ + if (*info.type == GSObjCTypeStructureEnd) + this->size += GSObjCGetPadding (info.size, info.alignment); + else + this->size += GSObjCPadSize (info.size, info.alignment); + this->alignment = MAX(this->alignment, info.alignment); +} + +const char * +GSGetSizeAndAlignment (const char *type, size_t *sizep, uint8_t *alignp) +{ + InfoAccumulator accumulator = {0, 0}; + type = GSObjCParseTypeSpecification (type, + (GSObjCTypeParserDelegate)&InfoAccumulatorAddInfo, + &accumulator, + GSObjCReportArrayOnceMask); + if (sizep) + { + *sizep = accumulator.size; + } + if (alignp) + { + *alignp = accumulator.alignment; + } + return type; +} + + +#if defined (NeXT_RUNTIME) + +/* emulate GNU API */ + +typedef struct SizeInfoAccumulator +{ + size_t size; + unsigned depth; +} SizeInfoAccumulator; + +static void +SizeInfoAccumulatorAddInfo (SizeInfoAccumulator *this, GSObjCTypeInfo info) +{ + /* we wait until typespec's last element and save it's unaligned size */ + switch (*info.type) + { + case GSObjCTypeArrayBegin: + case GSObjCTypeStructureBegin: + case GSObjCTypeUnionBegin: + ++this->depth; + break; + case GSObjCTypeArrayEnd: + case GSObjCTypeStructureEnd: + case GSObjCTypeUnionEnd: + --this->depth; + break; + default: + break; + } + if (!this->depth) + { + this->size += info.size; + } +} + +int +objc_sizeof_type (const char* type) +{ + SizeInfoAccumulator accumulator = {0, 0}; + GSObjCParseTypeSpecification (type, + (GSObjCTypeParserDelegate)&SizeInfoAccumulatorAddInfo, + &accumulator, + GSObjCReportArrayOnceMask); + return (int)accumulator.size; +} + +int +objc_alignof_type (const char* type) +{ + uint8_t alignment; + GSGetSizeAndAlignment (type, NULL, &alignment); + return (int)alignment; +} + +int +objc_aligned_size (const char* type) +{ + size_t size; + GSGetSizeAndAlignment (type, &size, NULL); + return (int)size; +} + +int +objc_promoted_size (const char* type) +{ + size_t size; + GSGetSizeAndAlignment (type, &size, NULL); + return (int)GSObjCPadSize (size, sizeof(void *)); +} + +/* we should not instantiate this function more than once */ +static const char * +GetQualifiersInst (const char *cursor, uint8_t *qualifiers) +{ + return GetQualifiers (cursor, qualifiers); +} + +/* we should not instantiate this function more than once */ +static const char * +SkipTypeInst (const char *cursor) +{ + return SkipType(cursor); +} + +unsigned +objc_get_type_qualifiers (const char* type) +{ + uint8_t qualifiers; + GetQualifiersInst (type, &qualifiers); + return qualifiers; +} + +const char * +objc_skip_type_qualifiers (const char* type) +{ + uint8_t qualifiers; + return GetQualifiersInst (type, &qualifiers); +} + +const char * +objc_skip_typespec (const char* type) +{ + uint8_t qualifiers; + type = GetQualifiersInst (type, &qualifiers); + return SkipTypeInst (type); +} + +const char * +objc_skip_offset (const char* type) +{ + if (*type == '+' || *type == '-') + { + type++; + } + while (*type >= '0' && *type <= '9') + { + type++; + } + return type; +} + +const char * +objc_skip_argspec (const char* type) +{ + type = SkipTypeInst (type); + return objc_skip_offset (type); +} + +static void +objc_layout_structure_append_info(struct objc_struct_layout *this, + GSObjCTypeInfo info) +{ + if (this->count == this->allocated) + { + this->info = realloc(this->info, sizeof(GSObjCTypeInfo) * (this->allocated *= 2)); + } + this->info[this->count] = info; + ++this->count; +} + +static void +objc_layout_structure_parser_delegate(struct objc_struct_layout *this, + GSObjCTypeInfo info) +{ + unsigned initialDepth = this->depth; + switch (*info.type) + { + case GSObjCTypeArrayEnd: + case GSObjCTypeStructureEnd: + case GSObjCTypeUnionEnd: + { + if (--this->depth == 1) + { + this->info[this->count - 1].size = info.size; + this->info[this->count - 1].alignment = info.alignment; + } + break; + } + case GSObjCTypeArrayBegin: + case GSObjCTypeStructureBegin: + case GSObjCTypeUnionBegin: + ++this->depth; + default: + if (initialDepth == 1) + { + objc_layout_structure_append_info(this, info); + } + break; + } +} + +void +objc_layout_structure (const char *type, + struct objc_struct_layout *layout) +{ + *layout = (struct objc_struct_layout) + { + malloc(8 * sizeof(GSObjCTypeInfo)), + -1, 0, 8, 0, 0, 0 + }; + GSObjCParseTypeSpecification(type, + (GSObjCTypeParserDelegate)&objc_layout_structure_parser_delegate, + layout, + GSObjCReportArrayOnceMask); +} + +BOOL +objc_layout_structure_next_member (struct objc_struct_layout *layout) +{ + return ++layout->position < layout->count; +} + +void +objc_layout_structure_get_info (struct objc_struct_layout *layout, + unsigned int *offset, + unsigned int *align, + const char **type) +{ + GSObjCTypeInfo info = layout->info[layout->position]; + + if (offset) + { + *offset = layout->offset; + } + if (align) + { + *align = info.alignment; + } + if (type) + { + *type = info.type; + } + + layout->offset += GSObjCPadSize(info.size, info.alignment); + layout->alignment = MAX(layout->alignment, info.alignment); +} + +void +objc_layout_finish_structure (struct objc_struct_layout *layout, + unsigned int *size, + unsigned int *align) +{ + if (size) + { + *size = (unsigned int) GSObjCPadSize(layout->offset, layout->alignment); + } + if (align) + { + *align = layout->alignment; + } + free(layout->info); +} + +#endif /* NeXT_RUNTIME */ diff --git a/configure b/configure index 0e0d5b192..dc78cae4b 100755 --- a/configure +++ b/configure @@ -3394,6 +3394,15 @@ LDFLAGS="$LDFLAGS -L$GNUSTEP_SYSTEM_LIBRARIES -L$GNUSTEP_NETWORK_LIBRARIES -L$GN #-------------------------------------------------------------------- # Find the compiler #-------------------------------------------------------------------- +if test "$CC" = ""; then + CC=`gnustep-config --variable=CC` +fi +if test "$CPP" = ""; then + CPP=`gnustep-config --variable=CPP` +fi +if test "$CXX" = ""; then + CXX=`gnustep-config --variable=CXX` +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' diff --git a/configure.ac b/configure.ac index 6222e70bd..572519ef5 100644 --- a/configure.ac +++ b/configure.ac @@ -1048,6 +1048,15 @@ LDFLAGS="$LDFLAGS -L$GNUSTEP_SYSTEM_LIBRARIES -L$GNUSTEP_NETWORK_LIBRARIES -L$GN #-------------------------------------------------------------------- # Find the compiler #-------------------------------------------------------------------- +if test "$CC" = ""; then + CC=`gnustep-config --variable=CC` +fi +if test "$CPP" = ""; then + CPP=`gnustep-config --variable=CPP` +fi +if test "$CXX" = ""; then + CXX=`gnustep-config --variable=CXX` +fi AC_PROG_CC AC_PROG_CPP AC_USE_SYSTEM_EXTENSIONS