@@ -1778,20 +1778,130 @@ double precise_xstrtod(const char *str, char **endptr, char decimal,
1778
1778
return number ;
1779
1779
}
1780
1780
1781
+ /* copy a decimal number string in form `decimal` and `tsep` and `sci` as
1782
+ decimal point, thousands separator and sci exponent character to a an
1783
+ equivalent c-locale decimal string (striping tsep, replacing `decimal`
1784
+ with '.' and sci with 'e'.
1785
+ */
1786
+
1787
+ char * str_copy_decimal_str_c (const char * s , char * * endpos , char decimal , char tsep , char sci ) {
1788
+ #define IS_TSEP (c ) (tsep != '\0' && c == tsep)
1789
+ ssize_t size = 0 ;
1790
+ const char * p = s ;
1791
+ // First count how many characters we can consume.
1792
+ // Leading sign
1793
+ if (* p == '+' || * p == '-' ) p ++ ;
1794
+ // Integer part
1795
+ while (isdigit_ascii (* p )) {
1796
+ p ++ ;
1797
+ p += IS_TSEP (* p );
1798
+ }
1799
+ // Fractional part
1800
+ if (* p == decimal ) {
1801
+ p ++ ;
1802
+ while (isdigit_ascii (* p )) {
1803
+ p ++ ;
1804
+ p += IS_TSEP (* p );
1805
+ }
1806
+ }
1807
+ // Exponent part
1808
+ if (toupper_ascii (* p ) == toupper_ascii (sci )) {
1809
+ p ++ ;
1810
+ // Exponent sign
1811
+ if (* p == '+' || * p == '-' ) p ++ ;
1812
+ // Exponent
1813
+ while (isdigit_ascii (* p )) {
1814
+ p ++ ;
1815
+ p += IS_TSEP (* p );
1816
+ }
1817
+ }
1818
+
1819
+ size = p - s ;
1820
+ char * pc = strndup (s , size );
1821
+ char * dst = pc ;
1822
+ p = s ;
1823
+
1824
+ // Copy leading sign
1825
+ if (* p == '+' || * p == '-' ) {
1826
+ * dst ++ = * p ++ ;
1827
+ }
1828
+ // Copy integer part
1829
+ while (isdigit_ascii (* p )) {
1830
+ * dst ++ = * p ++ ;
1831
+ p += IS_TSEP (* p );
1832
+ }
1833
+ // Copy factional part, replacing `decimal` with '.'
1834
+ if (* p == decimal ) {
1835
+ * dst ++ = '.' ;
1836
+ p ++ ;
1837
+ while (isdigit_ascii (* p )) {
1838
+ * dst ++ = * p ++ ;
1839
+ p += IS_TSEP (* p );
1840
+ }
1841
+ }
1842
+ // Copy exponent replacing `sci` with 'e'
1843
+ if (toupper_ascii (* p ) == toupper_ascii (sci )) {
1844
+ * dst ++ = 'e' ;
1845
+ p ++ ;
1846
+ // Copy leading exponent sign
1847
+ if (* p == '+' || * p == '-' ) {
1848
+ * dst ++ = * p ++ ;
1849
+ }
1850
+ // Exponent
1851
+ while (isdigit_ascii (* p )) {
1852
+ * dst ++ = * p ++ ;
1853
+ p += IS_TSEP (* p );
1854
+ }
1855
+ }
1856
+ * dst = '\0' ;
1857
+ if (endpos != NULL ) {
1858
+ * endpos = (char * )p ;
1859
+ }
1860
+ return pc ;
1861
+ #undef IS_TSEP
1862
+ }
1863
+
1781
1864
double round_trip (const char * p , char * * q , char decimal , char sci , char tsep ,
1782
1865
int skip_trailing , int * error , int * maybe_int ) {
1866
+ char * pc = NULL ;
1867
+ // 'normalize' representation to C-locale; replace decimal with '.' and
1868
+ // remove t(housand)sep.
1869
+ char * endptr = NULL ;
1870
+ if (decimal != '.' || tsep != '\0' ) {
1871
+ pc = str_copy_decimal_str_c (p , & endptr , decimal , tsep , sci );
1872
+ }
1783
1873
// This is called from a nogil block in parsers.pyx
1784
1874
// so need to explicitly get GIL before Python calls
1785
1875
PyGILState_STATE gstate ;
1786
1876
gstate = PyGILState_Ensure ();
1787
-
1788
- double r = PyOS_string_to_double (p , q , 0 );
1877
+ double r ;
1878
+ if (pc != NULL ) {
1879
+ char * endpc = NULL ;
1880
+ r = PyOS_string_to_double (pc , & endpc , 0 );
1881
+ // PyOS_string_to_double needs to consume the whole string
1882
+ if (endpc == pc + strlen (pc )) {
1883
+ if (q != NULL ) {
1884
+ // report endptr from source string (p)
1885
+ * q = (char * ) endptr ;
1886
+ }
1887
+ } else {
1888
+ * error = -1 ;
1889
+ if (q != NULL ) {
1890
+ // p and pc are different len due to tsep removal. Can't report
1891
+ // how much it has consumed of p. Just rewind to beginning.
1892
+ * q = (char * )p ;
1893
+ }
1894
+ }
1895
+ } else {
1896
+ r = PyOS_string_to_double (p , q , 0 );
1897
+ }
1789
1898
if (maybe_int != NULL ) * maybe_int = 0 ;
1790
1899
if (PyErr_Occurred () != NULL ) * error = -1 ;
1791
1900
else if (r == Py_HUGE_VAL ) * error = (int )Py_HUGE_VAL ;
1792
1901
PyErr_Clear ();
1793
1902
1794
1903
PyGILState_Release (gstate );
1904
+ free (pc );
1795
1905
return r ;
1796
1906
}
1797
1907
0 commit comments