Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/notes/bugfix-21476.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Ensure "the extents of tArray" returns empty if the keys of tArray are not integers
5 changes: 3 additions & 2 deletions engine/src/exec-array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,15 +970,16 @@ bool MCArraysSplitIndexes(MCNameRef p_key, integer_t*& r_indexes, uindex_t& r_co
return false;

MCAutoNumberRef t_number;
if (!MCNumberParse(*t_substring, &t_number))

if (!MCNumberParseInteger(*t_substring, &t_number))
{
if (!t_indexes . Push(0))
return false;

r_all_integers = false;
break;
}

if (!t_indexes . Push(MCNumberFetchAsInteger(*t_number)))
return false;

Expand Down
1 change: 1 addition & 0 deletions libfoundation/include/foundation.h
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,7 @@ MC_DLLEXPORT bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offs

MC_DLLEXPORT bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number);
MC_DLLEXPORT bool MCNumberParse(MCStringRef string, MCNumberRef& r_number);
MC_DLLEXPORT bool MCNumberParseInteger(MCStringRef string, MCNumberRef& r_number);
MC_DLLEXPORT bool MCNumberParseUnicodeChars(const unichar_t *chars, uindex_t char_count, MCNumberRef& r_number);

#if defined(__HAS_CORE_FOUNDATION__)
Expand Down
215 changes: 125 additions & 90 deletions libfoundation/src/foundation-number.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */

////////////////////////////////////////////////////////////////////////////////

// Forward declarations of internal utility functions

static bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, bool p_integer_only, uindex_t &r_length_used, MCNumberRef &r_number);
static bool __MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number);
static bool __MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, bool p_integer_only, MCNumberRef& r_number);

////////////////////////////////////////////////////////////////////////////////

MC_DLLEXPORT_DEF
bool MCNumberCreateWithInteger(integer_t p_value, MCNumberRef& r_number)
{
Expand Down Expand Up @@ -126,31 +134,101 @@ compare_t MCNumberCompareTo(MCNumberRef self, MCNumberRef p_other_self)
return 0;
}

bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, uindex_t &r_length_used, MCNumberRef &r_number)
/////////////////////////////////////////////////////////////////////////////////

MC_DLLEXPORT_DEF
bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number)
{
return __MCNumberParseOffset(p_string, offset, char_count, false, r_number);
}

MC_DLLEXPORT_DEF
bool MCNumberParse(MCStringRef p_string, MCNumberRef &r_number)
{
return __MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), false, r_number);
}

MC_DLLEXPORT_DEF
bool MCNumberParseInteger(MCStringRef p_string, MCNumberRef &r_number)
{
return __MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), true, r_number);
}

MC_DLLEXPORT_DEF
bool MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, MCNumberRef& r_number)
{
return __MCNumberParseUnicodeChars(p_chars, p_char_count, false, r_number);
}

MC_DLLEXPORT_DEF
bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number)
{
bool t_success;
t_success = true;

MCNumberRef t_number;
t_number = nil;
char *t_buffer;
t_buffer = nil;

const char *t_native_string;
t_native_string = nil;

uindex_t t_length;
t_length = MCStringGetLength(p_string);

if (offset > t_length)
offset = t_length;

if (MCStringIsNative(p_string))
t_native_string = (const char*)MCStringGetNativeCharPtr(p_string) + offset;
else
{
t_success = MCMemoryNewArray(t_length - offset + 1, t_buffer);

uindex_t t_native_char_count;
if (t_success)
t_success = MCUnicodeCharsMapToNative(MCStringGetCharPtr(p_string) + offset, t_length - offset, (char_t*)t_buffer, t_native_char_count, '?');

t_native_string = t_buffer;
}

if (t_success)
t_success = __MCNumberParseNativeString(t_native_string, t_length - offset, false, false, r_chars_used, r_number);

MCMemoryDeleteArray(t_buffer);

return t_success;
}

////////////////////////////////////////////////////////////////////////////////

static bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p_full_string, bool p_integer_only, uindex_t &r_length_used, MCNumberRef &r_number)
{
bool t_success;
t_success = true;

MCNumberRef t_number;
t_number = nil;

uinteger_t t_base;
t_base = 10;

const char *t_string;
t_string = p_string;

if (p_length > 2 &&
p_string[0] == '0' &&
(p_string[1] == 'x' || p_string[1] == 'X'))
{
// If the string begins with 0x then parse as hex, and discard first two chars
t_base = 16;
t_string += 2;
if (!p_integer_only)
{
if (p_length > 2 &&
p_string[0] == '0' &&
(p_string[1] == 'x' || p_string[1] == 'X'))
{
// If the string begins with 0x then parse as hex, and discard first two chars
t_base = 16;
t_string += 2;
}
}

errno = 0;

char *t_end;
t_end = nil;

Expand All @@ -166,13 +244,17 @@ bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p
#endif

t_success = (errno != ERANGE) && (p_full_string ? (t_end - p_string == (ptrdiff_t)p_length) : (t_end != t_string));

if (!t_success && p_integer_only)
return false;

if (t_success)
t_success = MCNumberCreateWithInteger(t_integer, t_number);
// If parsing as base 10 unsigned integer failed, try to parse as real.
else if (t_base == 10)
{
errno = 0;

real64_t t_real;
t_real = strtod(p_string, &t_end);

Expand All @@ -181,18 +263,17 @@ bool __MCNumberParseNativeString(const char *p_string, uindex_t p_length, bool p
if (t_success)
t_success = MCNumberCreateWithReal(t_real, t_number);
}
if (t_success)
{
r_number = t_number;
r_length_used = t_end - p_string;
}
return t_success;
if (t_success)
{
r_number = t_number;
r_length_used = t_end - p_string;
}
return t_success;
}

MC_DLLEXPORT_DEF
bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, MCNumberRef &r_number)
static bool __MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_count, bool p_integer_only, MCNumberRef &r_number)
{
uindex_t length = MCStringGetLength(p_string);
if (offset > length)
Expand All @@ -207,83 +288,37 @@ bool MCNumberParseOffset(MCStringRef p_string, uindex_t offset, uindex_t char_co
bool t_success;
t_success = false;

uindex_t t_length_used;
t_length_used = 0;

t_success = __MCNumberParseNativeString((const char*)MCStringGetNativeCharPtr(p_string) + offset, char_count, true, t_length_used, r_number);

return t_success;
}

MC_DLLEXPORT_DEF
bool MCNumberParse(MCStringRef p_string, MCNumberRef &r_number)
{
return MCNumberParseOffset(p_string, 0, MCStringGetLength(p_string), r_number);
uindex_t t_length_used;
t_length_used = 0;

t_success = __MCNumberParseNativeString((const char*)MCStringGetNativeCharPtr(p_string) + offset, char_count, true, p_integer_only, t_length_used, r_number);

return t_success;
}

MC_DLLEXPORT_DEF
bool MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, MCNumberRef& r_number)
static bool __MCNumberParseUnicodeChars(const unichar_t *p_chars, uindex_t p_char_count, bool p_integer_only, MCNumberRef& r_number)
{
char *t_native_chars;
if (!MCMemoryNewArray(p_char_count + 1, t_native_chars))
return false;
char *t_native_chars;
if (!MCMemoryNewArray(p_char_count + 1, t_native_chars))
return false;

uindex_t t_native_char_count;
MCUnicodeCharsMapToNative(p_chars, p_char_count, (char_t *)t_native_chars, t_native_char_count, '?');
uindex_t t_native_char_count;
MCUnicodeCharsMapToNative(p_chars, p_char_count, (char_t *)t_native_chars, t_native_char_count, '?');

bool t_success;
t_success = false;

uindex_t t_length_used;
t_length_used = 0;

t_success = __MCNumberParseNativeString(t_native_chars, p_char_count, true, t_length_used, r_number);
bool t_success;
t_success = false;

MCMemoryDeleteArray(t_native_chars);
uindex_t t_length_used;
t_length_used = 0;

return t_success;
}

MC_DLLEXPORT_DEF
bool MCNumberParseOffsetPartial(MCStringRef p_string, uindex_t offset, uindex_t &r_chars_used, MCNumberRef &r_number)
{
bool t_success;
t_success = true;

char *t_buffer;
t_buffer = nil;

const char *t_native_string;
t_native_string = nil;

uindex_t t_length;
t_length = MCStringGetLength(p_string);

if (offset > t_length)
offset = t_length;

if (MCStringIsNative(p_string))
t_native_string = (const char*)MCStringGetNativeCharPtr(p_string) + offset;
else
{
t_success = MCMemoryNewArray(t_length - offset + 1, t_buffer);

uindex_t t_native_char_count;
if (t_success)
t_success = MCUnicodeCharsMapToNative(MCStringGetCharPtr(p_string) + offset, t_length - offset, (char_t*)t_buffer, t_native_char_count, '?');

t_native_string = t_buffer;
}

if (t_success)
t_success = __MCNumberParseNativeString(t_native_string, t_length - offset, false, r_chars_used, r_number);

MCMemoryDeleteArray(t_buffer);

return t_success;
t_success = __MCNumberParseNativeString(t_native_chars, p_char_count, true, p_integer_only, t_length_used, r_number);

MCMemoryDeleteArray(t_native_chars);

return t_success;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////

bool __MCNumberCopyDescription(__MCNumber *self, MCStringRef& r_string)
{
Expand Down
19 changes: 19 additions & 0 deletions tests/lcs/core/array/array.livecodescript
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,25 @@ on TestExtents
TestAssert "Extents of dimensional arrays", the extents of tDimensionalArray is tExpectedExtents
end TestExtents

on TestExtentsDecimal
local tArray
repeat with i=1 to 5
put "true" into tArray[i]
end repeat
put "false" into tArray[1.0]

TestAssert "Extents of array with a decimal key", the extents of tArray is empty

delete variable tArray[1.0]
local tSequenceKeys
put __keysForArray(kSequenceArray) into tSequenceKeys
TestAssert "Extents of array without a decimal key", the extents of tArray is (item 1 of tSequenceKeys, item -1 of tSequenceKeys)

put "false" into tArray[pi]
TestAssert "Extents of array with another decimal key", the extents of tArray is empty

end TestExtentsDecimal

on __testIsAmong pUseIsAmong
local tArray, tKeyList, tKeys

Expand Down