From 1570489962a604475cc91c7b9517a62737903a6d Mon Sep 17 00:00:00 2001 From: Ryan Krug Date: Sat, 26 Jul 2025 07:10:47 -0500 Subject: [PATCH 1/5] yeah --- ext/obj_ext/RIGSCore.m | 251 ++++++++++++++++++++++++++---------- ext/obj_ext/RIGSUtilities.h | 2 + ext/obj_ext/RIGSUtilities.m | 124 +++++++++++++++++- 3 files changed, 309 insertions(+), 68 deletions(-) diff --git a/ext/obj_ext/RIGSCore.m b/ext/obj_ext/RIGSCore.m index 8cd75bb..9b0c02e 100644 --- a/ext/obj_ext/RIGSCore.m +++ b/ext/obj_ext/RIGSCore.m @@ -168,10 +168,6 @@ type = rb_objc_skip_type_qualifiers(type); - if (strcmp(type, "@?") == 0) { - return &ffi_type_pointer; - } - if (*type == _C_STRUCT_B) { inStructCount = rb_objc_struct_type_arity(type); @@ -191,6 +187,46 @@ return inStruct; } + if (*type == _C_ARY_B) { + while (isdigit((unsigned char)*++type)) { + inStructCount = (inStructCount << 3) + (inStructCount << 1) + (*type - '0'); + } + + inStruct = (ffi_type *)malloc(sizeof(ffi_type)); + inStruct->size = 0; + inStruct->alignment = 0; + inStruct->type = FFI_TYPE_STRUCT; + inStruct->elements = malloc((inStructCount + 1) * sizeof(ffi_type *)); + + while (*type != _C_ARY_E) { + inStruct->elements[inStructIndex++] = rb_objc_ffi_type_for_type(type); + type = rb_objc_skip_typespec(type); + } + inStruct->elements[inStructIndex] = NULL; + + return inStruct; + } + + if (*type == _C_BFLD) { + while (isdigit((unsigned char)*++type)) { + inStructCount = (inStructCount << 3) + (inStructCount << 1) + (*type - '0'); + if (*(type + 1) == _C_BFLD) type++; + } + + switch(inStructCount) { + case 64: + return &ffi_type_uint64; + case 32: + return &ffi_type_uint32; + case 16: + return &ffi_type_uint16; + case 8: + return &ffi_type_uint8; + default: + return NULL; + } + } + switch (*type) { case _C_ID: case _C_CLASS: @@ -213,10 +249,10 @@ return &ffi_type_uint; case _C_LNG: return &ffi_type_slong; - case _C_LNG_LNG: - return &ffi_type_sint64; case _C_ULNG: return &ffi_type_ulong; + case _C_LNG_LNG: + return &ffi_type_sint64; case _C_ULNG_LNG: return &ffi_type_uint64; case _C_FLT: @@ -618,6 +654,15 @@ object by calling rb_objc_release() */ type = rb_objc_skip_type_qualifiers(type); + // what if we made our own where by we dont + // offset (zero) when we encounter a bit field + // then we just keep bit masking the where? + // we'd need to know though to offset at the + // last one I think though... bummer... + // + // also is there like a max size we can + // support to just force the int size we + // bit mask with? say uint32_t? NSGetSizeAndAlignment(type, &tsize, &align); offset = ROUND(offset, align); @@ -781,31 +826,14 @@ object by calling rb_objc_release() */ } } -static NSMethodSignature* -rb_objc_signature_with_format_string(NSMethodSignature *signature, const char *formatString, int nbArgsExtra) +static void +rb_objc_type_extend(const char *types, const char *formatString, int nbArgsExtra, char *objcTypes) { - char objcTypes[128]; - uint8_t objcTypesIndex; + size_t objcTypesIndex; size_t formatStringLength; - const char *type; - size_t nbArgs; size_t i; - nbArgs = [signature numberOfArguments]; - objcTypesIndex = 0; - - type = [signature methodReturnType]; - while (*type) { - objcTypes[objcTypesIndex++] = *type++; - } - - for(i=0; i 0) { - NSInteger formatStringIndex; - const char *formatString; - + + if (nbArgsExtra > 0) { formatStringIndex = (NSInteger)NSMapGet(knownFormatStrings, (void*)hash) - 1; if (formatStringIndex != -1 && TYPE(rigs_argv[formatStringIndex]) == T_STRING) { formatString = rb_string_value_cstr(&rigs_argv[formatStringIndex]); @@ -1026,8 +1060,10 @@ object by calling rb_objc_release() */ else { formatString = ""; } - signature = rb_objc_signature_with_format_string(signature, formatString, nbArgsExtra); - nbArgs = (int)[signature numberOfArguments]; + + rb_objc_type_extend(types, formatString, nbArgsExtra, buf); + types = buf; + nbArgs = (int)rb_objc_type_arity(types); } args = alloca(sizeof(void*) * nbArgs); @@ -1037,10 +1073,10 @@ object by calling rb_objc_release() */ memset(arg_types, 0, sizeof(ffi_type*) * nbArgs); for (i=0;i 0) { + // NSLog(@"%s %lu", thing, size); + // } + + // NSLog(@"%lu", size); + + // NSDecimalNumber *num = [NSDecimalNumber decimalNumberWithString:@"3.14"]; + + // NSDecimal dec = [num decimalValue]; + + // {?=b8b4b1b1b18[8S]}16@0:8 + + // https://fuchsia.googlesource.com/third_party/swift-corelibs-foundation/+/refs/tags/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-10-06-a/Foundation/Decimal.swift + + // typedef struct { + // signed char exponent; // 8 - Signed exponent - -128 to 127 + // BOOL isNegative; // 4 - Is this negative? + // BOOL validNumber; // Is this a valid number? + // unsigned char length; // digits in mantissa. + // unsigned char cMantissa[2*NSDecimalMaxDigit]; + // } NSDecimal; + + // uint32_t bits = 0; + + // int32_t offsets[5] = { 8, 4, 1, 1, 18 }; + // int32_t values[5] = { -2, 1, 0, 1, 0 }; + // int32_t offset = 0; + + // for (int i=0; i<5; i++) { + // bits |= (((1 << offsets[i]) - 1) & values[i]) << offset; + // offset += offsets[i]; + // } + + // bits |= (((1 << 8) - 1) & -2) << 0; + // bits |= (((1 << 4) - 1) & 1) << 8; + // bits |= (((1 << 1) - 1) & 0) << 12; + // bits |= (((1 << 1) - 1) & 1) << 13; + // bits |= (((1 << 18) - 1) & 0) << 14; + + // unsigned short mantissa[8] = { 0 }; + // mantissa[0] = 314; + // mantissa[1] = 0; + // mantissa[2] = 0; + // mantissa[3] = 0; + // mantissa[4] = 0; + // mantissa[5] = 0; + // mantissa[6] = 0; + // mantissa[7] = 0; + + // void *data; + // data = malloc(sizeof(NSDecimal)); + // memset(data, 0, sizeof(NSDecimal)); + // memcpy(data, &bits, sizeof(uint32_t)); + // memcpy((uint8_t*)data + sizeof(uint32_t), &mantissa, sizeof(unsigned short) * 8); + + // dec = *(NSDecimal *)(data); + + // NSLog(@"%@", NSDecimalString(&dec, @".")); + + // size_t size = 0; + // NSGetSizeAndAlignment("[8S]", &size, NULL); + // NSLog(@"%s %lu %lu", @encode(BOOL*), size, sizeof(BOOL*)); + + // NSLog(@"%d", 31 >> 3); + + // bitfields + // NSNumber decimalValue {_NSDecimal=b8b4b1b1b18[8S]}@: YES + // DecimalNumber decimalNumberWithDecimal: @@:{_NSDecimal=b8b4b1b1b18[8S]} YES + // NSDecimalNumber decimalValue {_NSDecimal=b8b4b1b1b18[8S]}@: YES + // NSDecimalNumber initWithDecimal: @@:{_NSDecimal=b8b4b1b1b18[8S]} YES + // NSScanner scanDecimal: B@:^{_NSDecimal=b8b4b1b1b18[8S]} YES + + // consider loading (or backporting) + // QuartzCore -> CA* + // CoreFoundation -> CG* } diff --git a/ext/obj_ext/RIGSUtilities.h b/ext/obj_ext/RIGSUtilities.h index 5be64fb..3ad1473 100644 --- a/ext/obj_ext/RIGSUtilities.h +++ b/ext/obj_ext/RIGSUtilities.h @@ -44,10 +44,12 @@ unsigned long rb_objc_hash(const char *value); unsigned long rb_objc_hash_s(const char *value, unsigned long seed); unsigned long rb_objc_hash_struct(const char *value); unsigned long rb_objc_struct_type_arity(const char *type); +unsigned long rb_objc_type_arity(const char *type); const char *rb_objc_skip_type_qualifiers(const char *type); const char *rb_objc_skip_type_size(const char *type); const char *rb_objc_skip_type_sname(const char *type); const char *rb_objc_skip_type_uname(const char *type); const char *rb_objc_skip_typespec(const char *type); +const char *rb_objc_type_size(const char *type, size_t *size); #endif /* __RIGSUtilitis_h_GNUSTEP_RUBY_INCLUDE */ diff --git a/ext/obj_ext/RIGSUtilities.m b/ext/obj_ext/RIGSUtilities.m index e35f075..811a99d 100644 --- a/ext/obj_ext/RIGSUtilities.m +++ b/ext/obj_ext/RIGSUtilities.m @@ -272,6 +272,126 @@ return arity; } +unsigned long +rb_objc_type_arity(const char *type) +{ + unsigned long arity; + + arity = 0; + while((type = rb_objc_skip_typespec(type))) { + arity++; + } + + return arity; +} + + +const char * +rb_objc_type_size(const char *type, size_t *size) +{ + int count; + size_t tsize; + + count = 0; + tsize = 0; + type = rb_objc_skip_type_qualifiers(type); + + switch (*type) { + case _C_ID: + /* skip blocks */ + while (*++type == _C_UNDEF); + *size += sizeof(id); + return type; + case _C_CLASS: + *size += sizeof(Class); + return type + 1; + case _C_SEL: + *size += sizeof(SEL); + return type + 1; + case _C_BOOL: + *size += sizeof(BOOL); + return type + 1; + case _C_CHR: + *size += sizeof(char); + return type + 1; + case _C_UCHR: + *size += sizeof(unsigned char); + return type + 1; + case _C_CHARPTR: + case _C_ATOM: + *size += sizeof(char*); + return type + 1; + case _C_SHT: + *size += sizeof(short); + return type + 1; + case _C_USHT: + *size += sizeof(unsigned short); + return type + 1; + case _C_INT: + *size += sizeof(int); + return type + 1; + case _C_UINT: + *size += sizeof(unsigned int); + return type + 1; + case _C_LNG: + *size += sizeof(long); + return type + 1; + case _C_ULNG: + *size += sizeof(unsigned long); + return type + 1; + case _C_LNG_LNG: + *size += sizeof(long long); + return type + 1; + case _C_ULNG_LNG: + *size += sizeof(unsigned long long); + return type + 1; + case _C_FLT: + *size += sizeof(float); + return type + 1; + case _C_DBL: + *size += sizeof(double); + return type + 1; + case _C_VOID: + case _C_UNDEF: + return type + 1; + case _C_BFLD: + /* skip marker, sum bits until first non-marker */ + while (isdigit((unsigned char)*++type)) { + count = (count << 3) + (count << 1) + (*type - '0'); + if (*(type + 1) == _C_BFLD) type++; + } + *size += count >> 3; + return type; + case _C_ARY_B: + /* skip marker, multiply count by size elements until closing ']' */ + while (isdigit((unsigned char)*++type)) + count = (count << 3) + (count << 1) + (*type - '0'); + while (*type != _C_ARY_E) + type = rb_objc_type_size(type, &tsize); + *size += tsize * count; + return type + 1; + case _C_STRUCT_B: + /* skip name, size elements until closing '}' */ + type = rb_objc_skip_type_sname(type); + while (*type != _C_STRUCT_E) + type = rb_objc_type_size(type, size); + return type + 1; + case _C_UNION_B: + /* skip name, size elements until closing ')' */ + type = rb_objc_skip_type_uname(type); + while (*type != _C_UNION_E) + type = rb_objc_type_size(type, size); + return type + 1; + case _C_PTR: + /* skip the following typespec */ + type = rb_objc_skip_typespec(type + 1); + *size += sizeof(void*); + return type; + default: + return 0; + } +} + const char * rb_objc_skip_typespec(const char *type) { @@ -280,7 +400,7 @@ switch (*type) { case _C_ID: - /* skip blocks */; + /* skip blocks */ while (*++type == _C_UNDEF); return type; @@ -309,6 +429,8 @@ case _C_BFLD: /* skip number of bits */ while (isdigit((unsigned char)*++type)); + while (*type == _C_BFLD) + type = rb_objc_skip_typespec(type); return type; case _C_ARY_B: From 630c8772b6ef0a463d91cf7dcef79b8337df80c9 Mon Sep 17 00:00:00 2001 From: Ryan Krug Date: Sat, 26 Jul 2025 07:33:19 -0500 Subject: [PATCH 2/5] tweak --- ext/obj_ext/RIGSCore.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/obj_ext/RIGSCore.m b/ext/obj_ext/RIGSCore.m index 9b0c02e..d677bc8 100644 --- a/ext/obj_ext/RIGSCore.m +++ b/ext/obj_ext/RIGSCore.m @@ -833,10 +833,10 @@ object by calling rb_objc_release() */ size_t formatStringLength; size_t i; - objcTypesIndex = strlcat(objcTypes, types, strlen(types) + strlen(objcTypes) + 1); + objcTypesIndex = strlcpy(objcTypes, types, strlen(types) + strlen(objcTypes) + 1); formatStringLength = strlen(formatString); i = 0; - + while (i < formatStringLength) { if (formatString[i++] != '%') continue; if (i < formatStringLength && formatString[i] == '%') { @@ -1063,7 +1063,7 @@ object by calling rb_objc_release() */ rb_objc_type_extend(types, formatString, nbArgsExtra, buf); types = buf; - nbArgs = (int)rb_objc_type_arity(types); + nbArgs += nbArgsExtra; } args = alloca(sizeof(void*) * nbArgs); From 448db86ea9cfedaaa8ea08fe2a177844b0694702 Mon Sep 17 00:00:00 2001 From: Ryan Krug Date: Sun, 27 Jul 2025 06:53:24 -0500 Subject: [PATCH 3/5] more tweaks --- ext/obj_ext/RIGSCore.m | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ext/obj_ext/RIGSCore.m b/ext/obj_ext/RIGSCore.m index d677bc8..39e83a9 100644 --- a/ext/obj_ext/RIGSCore.m +++ b/ext/obj_ext/RIGSCore.m @@ -999,23 +999,23 @@ object by calling rb_objc_release() */ void **args; VALUE rb_arg; VALUE rb_retval; - ffi_cif cif; ffi_type **arg_types; + ffi_type *type; ffi_type *ret_type; + size_t len; size_t ret_len; + const char *atypes; + const char *rtypes; + ffi_cif cif; ffi_closure *closure; ffi_status status; void *closurePtr; struct rb_objc_block *block; ffi_cif closureCif; - ffi_type *type; - size_t len; - const char *ltypes; - const char *rtypes; NSInteger formatStringIndex; const char *formatString; - const char* blockObjcTypes; - char buf[256] = { '\0' }; + const char *blockObjcTypes; + char *buf; if (rcv != nil) { nbArgsAdjust = 2; @@ -1061,6 +1061,9 @@ object by calling rb_objc_release() */ formatString = ""; } + buf = alloca(sizeof(char) * 255); + memset(buf, '\0', sizeof(char) * 255); + rb_objc_type_extend(types, formatString, nbArgsExtra, buf); types = buf; nbArgs += nbArgsExtra; @@ -1120,10 +1123,10 @@ object by calling rb_objc_release() */ else { type = rb_objc_ffi_type_for_type(types); len = 0; - ltypes = types; + atypes = types; types = rb_objc_type_size(types, &len); data = alloca(len); - rb_objc_convert_to_objc(rigs_argv[i-nbArgsAdjust], &data, 0, ltypes); + rb_objc_convert_to_objc(rigs_argv[i-nbArgsAdjust], &data, 0, atypes); args[i] = data; arg_types[i] = type; } From 2ef21ffed03a8fe1367a7f107436daf2e540ea93 Mon Sep 17 00:00:00 2001 From: Ryan Krug Date: Sun, 27 Jul 2025 07:42:31 -0500 Subject: [PATCH 4/5] More crazy --- ext/obj_ext/RIGSCore.m | 90 +++++++------------------------------ ext/obj_ext/RIGSUtilities.h | 1 + ext/obj_ext/RIGSUtilities.m | 49 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 75 deletions(-) diff --git a/ext/obj_ext/RIGSCore.m b/ext/obj_ext/RIGSCore.m index 39e83a9..64c6112 100644 --- a/ext/obj_ext/RIGSCore.m +++ b/ext/obj_ext/RIGSCore.m @@ -826,78 +826,6 @@ object by calling rb_objc_release() */ } } -static void -rb_objc_type_extend(const char *types, const char *formatString, int nbArgsExtra, char *objcTypes) -{ - size_t objcTypesIndex; - size_t formatStringLength; - size_t i; - - objcTypesIndex = strlcpy(objcTypes, types, strlen(types) + strlen(objcTypes) + 1); - formatStringLength = strlen(formatString); - i = 0; - - while (i < formatStringLength) { - if (formatString[i++] != '%') continue; - if (i < formatStringLength && formatString[i] == '%') { - i++; - continue; - } - objcTypes[objcTypesIndex] = '\0'; - while (i < formatStringLength) { - switch (formatString[i++]) { - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - case 'c': - case 'C': - objcTypes[objcTypesIndex] = _C_INT; - break; - case 'D': - case 'O': - case 'U': - objcTypes[objcTypesIndex] = _C_LNG; - break; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - objcTypes[objcTypesIndex] = _C_DBL; - break; - case 's': - case 'S': - objcTypes[objcTypesIndex] = _C_CHARPTR; - break; - case 'p': - objcTypes[objcTypesIndex] = _C_PTR; - break; - case '@': - objcTypes[objcTypesIndex] = _C_ID; - break; - } - if (objcTypes[objcTypesIndex] != '\0') { - objcTypesIndex++; - if (--nbArgsExtra < 0) { - rb_raise(rb_eArgError, "too many tokens in the format string '%s' for the given argument(s)", formatString); - } - break; - } - } - } - - while (nbArgsExtra-- > 0) { - objcTypes[objcTypesIndex++] = _C_ID; - } - objcTypes[objcTypesIndex] = '\0'; -} - static void rb_objc_proxy_handler(ffi_cif *cif, void *ret, void **args, void *user_data) { @autoreleasepool { @@ -1016,6 +944,7 @@ object by calling rb_objc_release() */ const char *formatString; const char *blockObjcTypes; char *buf; + char keyChar; if (rcv != nil) { nbArgsAdjust = 2; @@ -1063,10 +992,21 @@ object by calling rb_objc_release() */ buf = alloca(sizeof(char) * 255); memset(buf, '\0', sizeof(char) * 255); - - rb_objc_type_extend(types, formatString, nbArgsExtra, buf); + len = strlcpy(buf, types, strlen(types) + strlen(buf) + 1); + + i = nbArgsExtra; + while (len < 255 && (formatString = rb_objc_format_keychar(formatString, &keyChar))) { + buf[len++] = keyChar; + nbArgs++; + if (--i < 0) { + rb_raise(rb_eArgError, "too many tokens in the format string for the given argument(s)"); + } + } + while (len < 255 && i-- > 0) { + buf[len++] = _C_ID; + nbArgs++; + } types = buf; - nbArgs += nbArgsExtra; } args = alloca(sizeof(void*) * nbArgs); diff --git a/ext/obj_ext/RIGSUtilities.h b/ext/obj_ext/RIGSUtilities.h index 3ad1473..b859083 100644 --- a/ext/obj_ext/RIGSUtilities.h +++ b/ext/obj_ext/RIGSUtilities.h @@ -51,5 +51,6 @@ const char *rb_objc_skip_type_sname(const char *type); const char *rb_objc_skip_type_uname(const char *type); const char *rb_objc_skip_typespec(const char *type); const char *rb_objc_type_size(const char *type, size_t *size); +const char *rb_objc_format_keychar(const char *format, char *keyChar); #endif /* __RIGSUtilitis_h_GNUSTEP_RUBY_INCLUDE */ diff --git a/ext/obj_ext/RIGSUtilities.m b/ext/obj_ext/RIGSUtilities.m index 811a99d..43347e3 100644 --- a/ext/obj_ext/RIGSUtilities.m +++ b/ext/obj_ext/RIGSUtilities.m @@ -462,3 +462,52 @@ return 0; } } + +const char * +rb_objc_format_keychar(const char *format, char *keyChar) +{ + char fmtChar; + + while ((fmtChar = *format++)) { + if (fmtChar != '%') continue; + switch(*format) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + case 'C': + *keyChar = _C_INT; + return format + 1; + case 'D': + case 'O': + case 'U': + *keyChar = _C_LNG; + return format + 1; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + *keyChar = _C_DBL; + return format + 1; + case 's': + case 'S': + *keyChar = _C_CHARPTR; + return format + 1; + case 'p': + *keyChar = _C_PTR; + return format + 1; + case '@': + *keyChar = _C_ID; + return format + 1; + } + } + + return 0; +} From aa5ac01f3ca10c36539df5eb37db0bb327d4e30c Mon Sep 17 00:00:00 2001 From: Ryan Krug Date: Sun, 27 Jul 2025 08:24:43 -0500 Subject: [PATCH 5/5] Support double percent --- ext/obj_ext/RIGSUtilities.m | 80 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/ext/obj_ext/RIGSUtilities.m b/ext/obj_ext/RIGSUtilities.m index 43347e3..ac11ff4 100644 --- a/ext/obj_ext/RIGSUtilities.m +++ b/ext/obj_ext/RIGSUtilities.m @@ -469,43 +469,49 @@ char fmtChar; while ((fmtChar = *format++)) { - if (fmtChar != '%') continue; - switch(*format) { - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - case 'c': - case 'C': - *keyChar = _C_INT; - return format + 1; - case 'D': - case 'O': - case 'U': - *keyChar = _C_LNG; - return format + 1; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - case 'a': - case 'A': - *keyChar = _C_DBL; - return format + 1; - case 's': - case 'S': - *keyChar = _C_CHARPTR; - return format + 1; - case 'p': - *keyChar = _C_PTR; - return format + 1; - case '@': - *keyChar = _C_ID; - return format + 1; + if (fmtChar != '%') continue; + if (*format == '%') { + format++; + continue; + } + while ((fmtChar = *format++)) { + switch(fmtChar) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + case 'C': + *keyChar = _C_INT; + return format; + case 'D': + case 'O': + case 'U': + *keyChar = _C_LNG; + return format; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + case 'a': + case 'A': + *keyChar = _C_DBL; + return format; + case 's': + case 'S': + *keyChar = _C_CHARPTR; + return format; + case 'p': + *keyChar = _C_PTR; + return format; + case '@': + *keyChar = _C_ID; + return format; + } } }