]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/io/uscanf_p.c
ICU-511.34.tar.gz
[apple/icu.git] / icuSources / io / uscanf_p.c
index 17e981387bcda2a9cc90144fc36f49151b26f07e..e6b22e326f26cb4ad509d3b5f369bb9344482234 100644 (file)
@@ -1,7 +1,7 @@
 /*
 *******************************************************************************
 *
-*   Copyright (C) 1998-2004, International Business Machines
+*   Copyright (C) 1998-2011, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
@@ -306,6 +306,7 @@ typedef struct u_scanf_info {
 } u_scanf_info;
 
 #define USCANF_NUM_FMT_HANDLERS 108
+#define USCANF_SYMBOL_BUFFER_SIZE 8
 
 /* We do not use handlers for 0-0x1f */
 #define USCANF_BASE_FMT_HANDLERS 0x20
@@ -332,6 +333,43 @@ u_scanf_skip_leading_ws(UFILE   *input,
     return count;
 }
 
+/* TODO: Is always skipping the prefix symbol as a positive sign a good idea in all locales? */
+static int32_t
+u_scanf_skip_leading_positive_sign(UFILE   *input,
+                                   UNumberFormat *format,
+                                   UErrorCode *status)
+{
+    UChar   c;
+    int32_t count = 0;
+    UBool isNotEOF;
+    UChar plusSymbol[USCANF_SYMBOL_BUFFER_SIZE];
+    int32_t symbolLen;
+    UErrorCode localStatus = U_ZERO_ERROR;
+
+    if (U_SUCCESS(*status)) {
+        symbolLen = unum_getSymbol(format,
+            UNUM_PLUS_SIGN_SYMBOL,
+            plusSymbol,
+            sizeof(plusSymbol)/sizeof(*plusSymbol),
+            &localStatus);
+
+        if (U_SUCCESS(localStatus)) {
+            /* skip all leading ws in the input */
+            while( (isNotEOF = ufile_getch(input, &c)) && (count < symbolLen && c == plusSymbol[count]) )
+            {
+                count++;
+            }
+
+            /* put the final character back on the input */
+            if(isNotEOF) {
+                u_fungetc(c, input);
+            }
+        }
+    }
+
+    return count;
+}
+
 static int32_t 
 u_scanf_simple_percent_handler(UFILE        *input,
                                u_scanf_spec_info *info,
@@ -366,6 +404,7 @@ u_scanf_count_handler(UFILE         *input,
         else
             *(int32_t*)(args[0].ptrValue) = (int32_t)(UINT32_MAX & info->fWidth);
     }
+    *argConverted = 0;
 
     /* we converted 0 args */
     return 0;
@@ -383,17 +422,18 @@ u_scanf_double_handler(UFILE        *input,
     double          num;
     UNumberFormat   *format;
     int32_t         parsePos    = 0;
+    int32_t         skipped;
     UErrorCode      status      = U_ZERO_ERROR;
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -406,11 +446,19 @@ u_scanf_double_handler(UFILE        *input,
     if(format == 0)
         return 0;
 
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
     /* parse the number */
     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
 
     if (!info->fSkipArg) {
-        *(double*)(args[0].ptrValue) = num;
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
     }
 
     /* mask off any necessary bits */
@@ -422,9 +470,11 @@ u_scanf_double_handler(UFILE        *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return parsePos;
+    return parsePos + skipped;
 }
 
+#define UPRINTF_SYMBOL_BUFFER_SIZE 8
+
 static int32_t
 u_scanf_scientific_handler(UFILE        *input,
                            u_scanf_spec_info *info,
@@ -437,17 +487,21 @@ u_scanf_scientific_handler(UFILE        *input,
     double          num;
     UNumberFormat   *format;
     int32_t         parsePos    = 0;
+    int32_t         skipped;
     UErrorCode      status      = U_ZERO_ERROR;
+    UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
+    int32_t srcLen, expLen;
+    UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -460,11 +514,50 @@ u_scanf_scientific_handler(UFILE        *input,
     if(format == 0)
         return 0;
 
+    /* set the appropriate flags on the formatter */
+
+    srcLen = unum_getSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        srcExpBuf,
+        sizeof(srcExpBuf),
+        &status);
+
+    /* Upper/lower case the e */
+    if (info->fSpec == (UChar)0x65 /* e */) {
+        expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            input->str.fBundle.fLocale,
+            &status);
+    }
+    else {
+        expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
+            srcExpBuf, srcLen,
+            input->str.fBundle.fLocale,
+            &status);
+    }
+
+    unum_setSymbol(format,
+        UNUM_EXPONENTIAL_SYMBOL,
+        expBuf,
+        expLen,
+        &status);
+
+
+
+
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
     /* parse the number */
     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
 
     if (!info->fSkipArg) {
-        *(double*)(args[0].ptrValue) = num;
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
     }
 
     /* mask off any necessary bits */
@@ -476,7 +569,7 @@ u_scanf_scientific_handler(UFILE        *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return parsePos;
+    return parsePos + skipped;
 }
 
 static int32_t
@@ -487,12 +580,13 @@ u_scanf_scidbl_handler(UFILE        *input,
                        int32_t      *fmtConsumed,
                        int32_t      *argConverted)
 {
-    int32_t        len;
+    int32_t       len;
     double        num;
     UNumberFormat *scientificFormat, *genericFormat;
     /*int32_t       scientificResult, genericResult;*/
     double        scientificResult, genericResult;
     int32_t       scientificParsePos = 0, genericParsePos = 0, parsePos = 0;
+    int32_t       skipped;
     UErrorCode    scientificStatus = U_ZERO_ERROR;
     UErrorCode    genericStatus = U_ZERO_ERROR;
 
@@ -504,13 +598,13 @@ u_scanf_scidbl_handler(UFILE        *input,
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -524,6 +618,9 @@ u_scanf_scidbl_handler(UFILE        *input,
     if(scientificFormat == 0 || genericFormat == 0)
         return 0;
 
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, genericFormat, &genericStatus);
+
     /* parse the number using each format*/
 
     scientificResult = unum_parseDouble(scientificFormat, input->str.fPos, len,
@@ -548,7 +645,12 @@ u_scanf_scidbl_handler(UFILE        *input,
     input->str.fPos += parsePos;
 
     if (!info->fSkipArg) {
-        *(double*)(args[0].ptrValue) = num;
+        if (info->fIsLong)
+            *(double*)(args[0].ptrValue) = num;
+        else if (info->fIsLongDouble)
+            *(long double*)(args[0].ptrValue) = num;
+        else
+            *(float*)(args[0].ptrValue) = (float)num;
     }
 
     /* mask off any necessary bits */
@@ -557,7 +659,7 @@ u_scanf_scidbl_handler(UFILE        *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return parsePos;
+    return parsePos + skipped;
 }
 
 static int32_t
@@ -572,18 +674,19 @@ u_scanf_integer_handler(UFILE       *input,
     void            *num        = (void*) (args[0].ptrValue);
     UNumberFormat   *format;
     int32_t         parsePos    = 0;
+    int32_t         skipped;
     UErrorCode      status      = U_ZERO_ERROR;
     int64_t         result;
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -596,6 +699,9 @@ u_scanf_integer_handler(UFILE       *input,
     if(format == 0)
         return 0;
 
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    skipped += u_scanf_skip_leading_positive_sign(input, format, &status);
+
     /* parse the number */
     result = unum_parseInt64(format, input->str.fPos, len, &parsePos, &status);
 
@@ -614,7 +720,7 @@ u_scanf_integer_handler(UFILE       *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return parsePos;
+    return parsePos + skipped;
 }
 
 static int32_t
@@ -651,7 +757,7 @@ u_scanf_percent_handler(UFILE       *input,
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -664,6 +770,9 @@ u_scanf_percent_handler(UFILE       *input,
     if(format == 0)
         return 0;
 
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    u_scanf_skip_leading_positive_sign(input, format, &status);
+
     /* parse the number */
     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
 
@@ -698,12 +807,13 @@ u_scanf_string_handler(UFILE        *input,
     char        *limit;
     UErrorCode  status  = U_ZERO_ERROR;
     int32_t     count;
+    int32_t     skipped = 0;
     UChar       c;
     UBool       isNotEOF = FALSE;
 
     /* skip all ws in the input */
     if (info->fIsString) {
-        u_scanf_skip_leading_ws(input, info->fPadChar);
+        skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
     }
 
     /* get the string one character at a time, truncating to the width */
@@ -762,7 +872,7 @@ u_scanf_string_handler(UFILE        *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return count;
+    return count + skipped;
 }
 
 static int32_t
@@ -791,12 +901,13 @@ u_scanf_ustring_handler(UFILE       *input,
     UChar   *arg     = (UChar*)(args[0].ptrValue);
     UChar   *alias     = arg;
     int32_t count;
+    int32_t skipped = 0;
     UChar   c;
     UBool   isNotEOF = FALSE;
 
     /* skip all ws in the input */
     if (info->fIsString) {
-        u_scanf_skip_leading_ws(input, info->fPadChar);
+        skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
     }
 
     /* get the string one character at a time, truncating to the width */
@@ -830,7 +941,7 @@ u_scanf_ustring_handler(UFILE       *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return count;
+    return count + skipped;
 }
 
 static int32_t
@@ -860,17 +971,18 @@ u_scanf_spellout_handler(UFILE          *input,
     double          num;
     UNumberFormat   *format;
     int32_t         parsePos    = 0;
+    int32_t         skipped;
     UErrorCode      status      = U_ZERO_ERROR;
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -883,6 +995,10 @@ u_scanf_spellout_handler(UFILE          *input,
     if(format == 0)
         return 0;
 
+    /* Skip the positive prefix. ICU normally can't handle this due to strict parsing. */
+    /* This is not applicable to RBNF. */
+    /*skipped += u_scanf_skip_leading_positive_sign(input, format, &status);*/
+
     /* parse the number */
     num = unum_parseDouble(format, input->str.fPos, len, &parsePos, &status);
 
@@ -899,7 +1015,7 @@ u_scanf_spellout_handler(UFILE          *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return parsePos;
+    return parsePos + skipped;
 }
 
 static int32_t
@@ -911,17 +1027,18 @@ u_scanf_hex_handler(UFILE       *input,
                     int32_t     *argConverted)
 {
     int32_t     len;
+    int32_t     skipped;
     void        *num    = (void*) (args[0].ptrValue);
     int64_t     result;
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -954,7 +1071,7 @@ u_scanf_hex_handler(UFILE       *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return len;
+    return len + skipped;
 }
 
 static int32_t
@@ -965,18 +1082,19 @@ u_scanf_octal_handler(UFILE         *input,
                       int32_t       *fmtConsumed,
                       int32_t       *argConverted)
 {
-    int32_t        len;
-    void            *num         = (void*) (args[0].ptrValue);
-    int64_t         result;
+    int32_t     len;
+    int32_t     skipped;
+    void        *num         = (void*) (args[0].ptrValue);
+    int64_t     result;
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1)
@@ -1000,7 +1118,7 @@ u_scanf_octal_handler(UFILE         *input,
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return len;
+    return len + skipped;
 }
 
 static int32_t
@@ -1012,55 +1130,25 @@ u_scanf_pointer_handler(UFILE       *input,
                         int32_t     *argConverted)
 {
     int32_t len;
+    int32_t skipped;
     void    *result;
     void    **p     = (void**)(args[0].ptrValue);
 
 
     /* skip all ws in the input */
-    u_scanf_skip_leading_ws(input, info->fPadChar);
+    skipped = u_scanf_skip_leading_ws(input, info->fPadChar);
 
     /* fill the input's internal buffer */
     ufile_fill_uchar_buffer(input);
 
     /* determine the size of the input's buffer */
-    len = input->str.fLimit - input->str.fPos;
+    len = (int32_t)(input->str.fLimit - input->str.fPos);
 
     /* truncate to the width, if specified */
     if(info->fWidth != -1) {
         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);
@@ -1073,14 +1161,12 @@ u_scanf_pointer_handler(UFILE       *input,
         *p = result;
     }
 
-#endif
-
     /* update the input's position to reflect consumed data */
     input->str.fPos += len;
 
     /* we converted 1 arg */
     *argConverted = !info->fSkipArg;
-    return len;
+    return len + skipped;
 }
 
 static int32_t