mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-29 16:01:38 +00:00
Add new type encoding parser by Ibadinov Marat, modified to build on gnu/linux
without warnings, using gcc. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@36813 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
060ba55854
commit
38ea0d2b27
6 changed files with 983 additions and 1 deletions
|
@ -1,3 +1,10 @@
|
|||
2013-07-03 Ibadinov Marat <ibadinov@me.com>
|
||||
|
||||
* Source/Additions/GNUmakefile:
|
||||
* Headers/GNUstepBase/GSTypeEncoding.c:
|
||||
* Headers/GNUstepBase/GSTypeEncoding.h:
|
||||
New type encoding parser.
|
||||
|
||||
2013-07-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Headers/Foundation/NSException.h:
|
||||
|
|
226
Headers/GNUstepBase/GSTypeEncoding.h
Normal file
226
Headers/GNUstepBase/GSTypeEncoding.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Objective-C type encoding support
|
||||
*
|
||||
* Copyright (C) 2012-2013 Free Software Foundation, Inc.
|
||||
*
|
||||
* Written by Marat Ibadinov <ibadinov@me.com>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#if defined (NeXT_RUNTIME)
|
||||
# include <objc/objc-runtime.h>
|
||||
#else
|
||||
# if defined (__GNU_LIBOBJC__)
|
||||
# include <objc/runtime.h>
|
||||
# else
|
||||
# include <objc/objc-api.h>
|
||||
# include <objc/encoding.h>
|
||||
# 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 */
|
|
@ -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
|
||||
|
|
729
Source/Additions/GSTypeEncoding.c
Normal file
729
Source/Additions/GSTypeEncoding.c
Normal file
|
@ -0,0 +1,729 @@
|
|||
/*
|
||||
* Objective-C type encoding support
|
||||
*
|
||||
* Copyright (C) 2012-2013 Free Software Foundation, Inc.
|
||||
*
|
||||
* Written by Marat Ibadinov <ibadinov@me.com>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#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 */
|
9
configure
vendored
9
configure
vendored
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue