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