1/* 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 the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along 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
28using 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
39istream &
40operator>> (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