blob: 9ff25ebef1a3e3117c09d1bbdfa295bd25a9a5bd [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/* operator>> -- C++-style input of mpf_t.
2
3Copyright 2001, 2003 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of either:
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14or
15
16 * the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
18 later version.
19
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see https://www.gnu.org/licenses/. */
30
31#include <cctype>
32#include <iostream>
33#include <string>
34#include <clocale> // for localeconv
35
36#include "gmp-impl.h"
37
38using namespace std;
39
40
41// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_float
42// in include/bits/locale_facets.tcc.
43//
44// There are no plans to accept hex or octal floats, not unless the standard
45// C++ library does so. Although such formats might be of use, it's
46// considered more important to be compatible with what the normal
47// operator>> does on "double"s etc.
48
49istream &
50operator>> (istream &i, mpf_ptr f)
51{
52 int base;
53 char c = 0;
54 string s;
55 bool ok = false;
56
57 // C decimal point, as expected by mpf_set_str
58 const char *lconv_point = GMP_DECIMAL_POINT;
59
60 // C++ decimal point
61#if HAVE_STD__LOCALE
62 const locale& loc = i.getloc();
63 char point_char = use_facet< numpunct<char> >(loc).decimal_point();
64#else
65 const char *point = lconv_point;
66 char point_char = *point;
67#endif
68
69 i.get(c); // start reading
70
71 if (i.flags() & ios::skipws) // skip initial whitespace
72 {
73 // C++ isspace
74#if HAVE_STD__LOCALE
75 const ctype<char>& ct = use_facet< ctype<char> >(loc);
76#define cxx_isspace(c) (ct.is(ctype_base::space,(c)))
77#else
78#define cxx_isspace(c) isspace(c)
79#endif
80
81 while (cxx_isspace(c) && i.get(c))
82 ;
83 }
84
85 if (c == '-' || c == '+') // sign
86 {
87 if (c == '-')
88 s = "-";
89 i.get(c);
90 }
91
92 base = 10;
93 __gmp_istream_set_digits(s, i, c, ok, base); // read the number
94
95 // look for the C++ radix point, but put the C one in for mpf_set_str
96 if (c == point_char)
97 {
98#if HAVE_STD__LOCALE
99 i.get(c);
100#else // lconv point can be multi-char
101 for (;;)
102 {
103 i.get(c);
104 point++;
105 if (*point == '\0')
106 break;
107 if (c != *point)
108 goto fail;
109 }
110#endif
111 s += lconv_point;
112 __gmp_istream_set_digits(s, i, c, ok, base); // read the mantissa
113 }
114
115 if (ok && (c == 'e' || c == 'E')) // exponent
116 {
117 s += c;
118 i.get(c);
119 ok = false; // exponent is mandatory
120
121 if (c == '-' || c == '+') // sign
122 {
123 s += c;
124 i.get(c);
125 }
126
127 __gmp_istream_set_digits(s, i, c, ok, base); // read the exponent
128 }
129
130 if (i.good()) // last character read was non-numeric
131 i.putback(c);
132 else if (i.eof() && ok) // stopped just before eof
133 i.clear(ios::eofbit);
134
135 if (ok)
136 ASSERT_NOCARRY (mpf_set_str(f, s.c_str(), base)); // extract the number
137 else
138 {
139 fail:
140 i.setstate(ios::failbit); // read failed
141 }
142
143 return i;
144}