END_TEST /** * The nature of vsnprintf makes it difficult to unit test using the * 'check' framework. For now, since c_local_snprintf is written in terms * of c_locale_vsnprintf, if the "sn" test succeeds, we assume "vsn" is * correct. * START_TEST (test_c_locale_vsnprintf) { } END_TEST */ START_TEST (test_c_locale_strtod) { const char *en = "2.72"; char* lc; char *endptr; lc = setlocale(LC_ALL, "de_DE"); /** * These tests will fail under some platforms because of a minimal * setlocale() implementation (e.g. Cygwin (see setlocale manpage)) * or limited number of default locales (e.g. Ubuntu based). * Thus these tests will be skipped when setlocale() returns * NULL. */ if ( lc != NULL ) { const char *de = "2,72"; endptr = NULL; fail_unless( util_isEqual(strtod(de, &endptr), 2.72) ); fail_unless( (endptr - de) == 4 ); fail_unless( errno != ERANGE ); } endptr = NULL; fail_unless( util_isEqual(c_locale_strtod(en, &endptr),2.72) ); fail_unless( (endptr - en) == 4 ); fail_unless( errno != ERANGE ); setlocale(LC_ALL, "C"); }
/** * Reads either a TT_INTEGER or a TT_REAL from the FormulaTokenizer into * the given Token. This is a supporting function for * FormulaTokenizer_nextToken(). * * This function assumes the character ft->formula[ft->pos] is either a * period or a digit. FormulaTokenizer_nextToken() ensures this * precondition before calling this function. * * Sign characters preceding the number are not recognized, but sign * characters in the exponent are recognized. * * A subtle error case: * * If the string starting with ft->formula[ft->pos] is some combination of * a '.', 'e|E' or '+|-' with no intervening digits, the token will be * marked as TT_UNKNOWN and t->value.ch set to ft->formula[ft->pos] * (a '.'). */ void FormulaTokenizer_getNumber (FormulaTokenizer_t *ft, Token_t *t) { char c; char endchar; char *endptr; unsigned int start, stop, len; unsigned int exppos = 0; unsigned int endpos = 0; unsigned int seendot = 0; unsigned int seenexp = 0; unsigned int seensgn = 0; start = ft->pos; c = ft->formula[ start ]; /** * ([0-9]+\.?[0-9]*|\.[0-9]+)([eE][-+]?[0-9]+)? */ while (1) { if (c == '.' && seendot == 0) { seendot = 1; } else if ((c == 'e' || c == 'E') && seenexp == 0) { seenexp = 1; exppos = ft->pos; } else if ((c == '+' || c == '-') && seenexp == 1 && seensgn == 0) { seensgn = 1; } else if (c < '0' || c > '9') { endchar = c; endpos = ft->pos; break; } c = ft->formula[ ++ft->pos ]; } /** * Temporarily terminate ft->formula will a NULL at the character just * beyond the end of the number. This prevents strtod() and strtol() * (below) from reading past the end of the number. * * This prevents at least one obscure bug where something like '3e 4' is * understood as one token 3e4 instead of two: 3e0 and 4. */ ft->formula[ endpos ] = '\0'; stop = ft->pos; len = stop - start; /** * If the token is composed only of some combination of '.', 'e|E' or * '+|-' mark it as TT_UNKNOWN. Otherwise, strtod() or strtol() should * be able to convert it, as all the syntax checking was performed above. */ if (len == (seendot + seenexp + seensgn)) { t->type = TT_UNKNOWN; t->value.ch = ft->formula[start]; } else if (seendot || seenexp) { /** * Temporarily "hide" the exponent part, so strtod below will convert * only the mantissa part. */ if (seenexp) { c = ft->formula[ exppos ]; ft->formula[ exppos ] = '\0'; } t->type = TT_REAL; t->value.real = c_locale_strtod(ft->formula + start, &endptr); /** * Convert the exponent part and "unhide" it. */ if (seenexp) { t->type = TT_REAL_E; t->exponent = strtol(ft->formula + exppos + 1, &endptr, 10); ft->formula[ exppos ] = c; } } else { t->type = TT_INTEGER; t->value.integer = strtol(ft->formula + start, &endptr, 10); } /** * Restore the character overwritten above. */ ft->formula[ endpos ] = endchar; }