From: <gha...@us...> - 2006-05-28 22:29:10
|
Update of /cvsroot/pypgsql/pypgsql In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17794 Modified Files: pgresult.c Log Message: Integrated patch #1224272. Use PyOS_ascii_strtod instead of strtod in order to be locale-agnostic. Index: pgresult.c =================================================================== RCS file: /cvsroot/pypgsql/pypgsql/pgresult.c,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** pgresult.c 2 Oct 2002 04:08:38 -0000 1.18 --- pgresult.c 28 May 2006 22:29:06 -0000 1.19 *************** *** 29,32 **** --- 29,34 ---- | Date Ini Description | | --------- --- ------------------------------------------------------- | + | 29MAY2006 gh Integrated patch #1224272. Use PyOS_ascii_strtod | + | instead of strtod in order to be locale-agnostic. | | 01OCT2002 gh HAVE_LONG_LONG => HAVE_LONG_LONG_SUPPORT | | 03FEB2002 bga Change the constant that is used to determine when to | *************** *** 111,114 **** --- 113,285 ---- /*--------------------------------------------------------------------------*/ + #if (PY_VERSION_HEX < 0x02040000) + + /* code stolen from Python 2.4 */ + + #include <locale.h> + + #define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \ + (c) == '\r' || (c) == '\t' || (c) == '\v') + #define ISDIGIT(c) ((c) >= '0' && (c) <= '9') + #define ISXDIGIT(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) + + /** + * PyOS_ascii_strtod: + * @nptr: the string to convert to a numeric value. + * @endptr: if non-%NULL, it returns the character after + * the last character used in the conversion. + * + * Converts a string to a #gdouble value. + * This function behaves like the standard strtod() function + * does in the C locale. It does this without actually + * changing the current locale, since that would not be + * thread-safe. + * + * This function is typically used when reading configuration + * files or other non-user input that should be locale independent. + * To handle input from the user you should normally use the + * locale-sensitive system strtod() function. + * + * If the correct value would cause overflow, plus or minus %HUGE_VAL + * is returned (according to the sign of the value), and %ERANGE is + * stored in %errno. If the correct value would cause underflow, + * zero is returned and %ERANGE is stored in %errno. + * + * This function resets %errno before calling strtod() so that + * you can reliably detect overflow and underflow. + * + * Return value: the #gdouble value. + **/ + double + PyOS_ascii_strtod(const char *nptr, + char **endptr) + { + char *fail_pos; + double val; + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + + /* g_return_val_if_fail (nptr != NULL, 0); */ + assert(nptr != NULL); + + fail_pos = NULL; + + locale_data = localeconv(); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen(decimal_point); + + assert(decimal_point_len != 0); + + decimal_point_pos = NULL; + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + p = nptr; + /* Skip leading space */ + while (ISSPACE(*p)) + p++; + + /* Skip leading optional sign */ + if (*p == '+' || *p == '-') + p++; + + if (p[0] == '0' && + (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + /* HEX - find the (optional) decimal point */ + + while (ISXDIGIT(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ISXDIGIT(*p)) + p++; + + if (*p == 'p' || *p == 'P') + p++; + if (*p == '+' || *p == '-') + p++; + while (ISDIGIT(*p)) + p++; + end = p; + } + } + else + { + while (ISDIGIT(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ISDIGIT(*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (ISDIGIT(*p)) + p++; + end = p; + } + } + /* For the other cases, we need not convert the decimal point */ + } + + /* Set errno to zero, so that we can distinguish zero results + and underflows */ + errno = 0; + + if (decimal_point_pos) + { + char *copy, *c; + + /* We need to convert the '.' to the locale specific decimal point */ + copy = malloc(end - nptr + 1 + decimal_point_len); + + c = copy; + memcpy(c, nptr, decimal_point_pos - nptr); + c += decimal_point_pos - nptr; + memcpy(c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod(copy, &fail_pos); + + if (fail_pos) + { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); + else + fail_pos = (char *)nptr + (fail_pos - copy); + } + + free(copy); + + } + else + val = strtod(nptr, &fail_pos); + + if (endptr) + *endptr = fail_pos; + + return val; + } + + #endif + + /*--------------------------------------------------------------------------*/ + PyObject *PgResult_New(PGresult *res, PgConnection *conn, int type) { *************** *** 624,628 **** case PG_FLOAT8: ! valueObj = Py_BuildValue("d", strtod(value, NULL)); break; --- 795,799 ---- case PG_FLOAT8: ! valueObj = Py_BuildValue("d", PyOS_ascii_strtod(value, NULL)); break; |