diff --git a/icu4c/source/io/ufmt_cmn.c b/icu4c/source/io/ufmt_cmn.c index 855f1475b7..e4e0903391 100644 --- a/icu4c/source/io/ufmt_cmn.c +++ b/icu4c/source/io/ufmt_cmn.c @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1998-2004, International Business Machines +* Copyright (C) 1998-2006, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -39,7 +39,7 @@ ufmt_digitvalue(UChar c) ((c>=LOWERCASE_A)&&(c<=LOWERCASE_Z)) || ((c>=UPPERCASE_A)&&(c<=UPPERCASE_Z)) ) { - return c - 0x0030 - (c >= 0x0041 ? (c >= 0x0061 ? 39 : 7) : 0); + return c - DIGIT_0 - (c >= 0x0041 ? (c >= 0x0061 ? 39 : 7) : 0); } else { @@ -56,8 +56,8 @@ ufmt_isdigit(UChar c, return (UBool)(digitVal < radix && digitVal >= 0); } -#define TO_UC_DIGIT(a) a <= 9 ? (0x0030 + a) : (0x0037 + a) -#define TO_LC_DIGIT(a) a <= 9 ? (0x0030 + a) : (0x0057 + a) +#define TO_UC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0037 + a) +#define TO_LC_DIGIT(a) a <= 9 ? (DIGIT_0 + a) : (0x0057 + a) void ufmt_64tou(UChar *buffer, @@ -81,7 +81,7 @@ ufmt_64tou(UChar *buffer, /* pad with zeroes to make it minDigits long */ if(minDigits != -1 && length < minDigits) { while(length < minDigits && length < *len) - buffer[length++] = 0x0030; /*zero padding */ + buffer[length++] = DIGIT_0; /*zero padding */ } /* reverse the buffer */ @@ -158,37 +158,64 @@ ufmt_uto64(const UChar *buffer, return result; } +#define NIBBLE_PER_BYTE 2 void * ufmt_utop(const UChar *buffer, int32_t *len) { - /* - TODO: Fix this code so that it will work with pointers that are 2<=sizeof(void*)<=16 - */ - const UChar *limit; - int32_t count; - int64_t result; + int32_t count, resultIdx, incVal, offset; + /* This union allows the pointer to be written as an array. */ + union { + void *ptr; + uint8_t bytes[sizeof(void*)]; + } result; - - /* intialize parameters */ - limit = buffer + *len; - count = 0; - result = 0; - - /* iterate through buffer */ - /* limit to sixteen iterations since that is the max that an int64_t can contain for pointer work */ - while(ufmt_isdigit(*buffer, 16) && buffer < limit) { - - /* read the next digit */ - result *= 16; - result += ufmt_digitvalue(*buffer++); - - /* increment our count */ + /* intialize variables */ + count = 0; + offset = 0; + result.ptr = NULL; + + /* Skip the leading zeros */ + while(buffer[count] == DIGIT_0 || u_isspace(buffer[count])) { + count++; + offset++; + } + + /* iterate through buffer, stop when you hit the end */ + while(ufmt_isdigit(buffer[count], 16) && count < *len) { + /* increment the count consumed */ ++count; } + + /* detect overflow */ + if (count - offset > (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE)) { + offset = count - (int32_t)(sizeof(void*)*NIBBLE_PER_BYTE); + } + /* Initialize the direction of the input */ +#if U_IS_BIG_ENDIAN + incVal = -1; + resultIdx = (int32_t)(sizeof(void*) - 1); +#else + incVal = 1; + resultIdx = 0; +#endif + /* Write how much was consumed. */ *len = count; - return (void *)result; + while(--count >= offset) { + /* Get the first nibble of the byte */ + uint8_t byte = (uint8_t)ufmt_digitvalue(buffer[count]); + + if (count > offset) { + /* Get the second nibble of the byte when available */ + byte = (uint8_t)(byte + (ufmt_digitvalue(buffer[--count]) << 4)); + } + /* Write the byte into the array */ + result.bytes[resultIdx] = byte; + resultIdx += incVal; + } + + return result.ptr; } UChar* diff --git a/icu4c/source/io/uscanf_p.c b/icu4c/source/io/uscanf_p.c index 6daf3501cf..7314770850 100644 --- a/icu4c/source/io/uscanf_p.c +++ b/icu4c/source/io/uscanf_p.c @@ -1031,37 +1031,6 @@ u_scanf_pointer_handler(UFILE *input, len = ufmt_min(len, info->fWidth); } -#ifdef OS400 - /* TODO: Fix this code so that it will work on all platforms */ - { - int64_t result[2]; - int32_t lenOrig = len; - - /* Make sure that we don't consume too much */ - if (len > (int32_t)(sizeof(int64_t)*2)) { - len = (int32_t)(sizeof(int64_t)*2); - } - - /* parse the pointer - set first half of big endian pointer */ - result[0] = (int64_t)ufmt_utop(input->str.fPos, &len); - - /* update the input's position to reflect consumed data */ - input->str.fPos += len; - len = lenOrig - len; - - /* Make sure that we don't consume too much */ - if (len > (int32_t)(sizeof(int64_t)*2)) { - len = (int32_t)(sizeof(int64_t)*2); - } - - /* parse the pointer - set second half of big endian pointer */ - result[1] = (int64_t)ufmt_utop(input->str.fPos, &len); - - if (!info->fSkipArg) { - p = *((void **)result); - } - } -#else /* Make sure that we don't consume too much */ if (len > (int32_t)(sizeof(void*)*2)) { len = (int32_t)(sizeof(void*)*2); @@ -1074,8 +1043,6 @@ u_scanf_pointer_handler(UFILE *input, *p = result; } -#endif - /* update the input's position to reflect consumed data */ input->str.fPos += len;