1 /****************************************************************************
2  * Core Library Version 1.7, August 2004
3  * Copyright (c) 1995-2004 Exact Computation Project
4  * All rights reserved.
5  *
6  * file: GmpIO.cpp
7  *                 Adapted from multi-files under /cxx in GMP's source distribution
8  *
9  * Zilin Du, 2003
10  *
11  * $URL: https://github.com/CGAL/cgal/blob/v5.3/CGAL_Core/include/CGAL/CORE/Gmp_impl.h $
12  * $Id: Gmp_impl.h 12fd01d 2020-09-21T08:54:29+02:00 Ahmed Essam
13  * SPDX-License-Identifier: LGPL-3.0-only
14  ***************************************************************************/
15 
16 /* Auxiliary functions for C++-style input of GMP types.
17 
18 Copyright 2001 Free Software Foundation, Inc.
19 
20 This file is part of the GNU MP Library.
21 
22 */
23 
24 #ifdef CGAL_HEADER_ONLY
25 #define CGAL_INLINE_FUNCTION inline
26 #else
27 #define CGAL_INLINE_FUNCTION
28 #endif
29 
30 #include <CGAL/CORE/Gmp.h>
31 #include <cctype>
32 #include <iostream>
33 #include <string>
34 #include <cstdio>
35 
36 namespace CORE {
37 
38 CGAL_INLINE_FUNCTION
39 int
__gmp_istream_set_base(std::istream & i,char & c,bool & zero,bool & showbase)40 __gmp_istream_set_base (std::istream &i, char &c, bool &zero, bool &showbase)
41 {
42   int base;
43   using std::ios;
44 
45   zero = showbase = false;
46   switch (i.flags() & ios::basefield)
47     {
48     case ios::dec:
49       base = 10;
50       break;
51     case ios::hex:
52       base = 16;
53       break;
54     case ios::oct:
55       base = 8;
56       break;
57     default:
58       showbase = true; // look for initial "0" or "0x" or "0X"
59       if (c == '0')
60         {
61           if (! i.get(c))
62             c = 0; // reset or we might loop indefinitely
63 
64           if (c == 'x' || c == 'X')
65             {
66               base = 16;
67               i.get(c);
68             }
69           else
70             {
71               base = 8;
72               zero = true; // if no other digit is read, the "0" counts
73             }
74         }
75       else
76         base = 10;
77       break;
78     }
79 
80   return base;
81 }
82 
83 CGAL_INLINE_FUNCTION
84 void
__gmp_istream_set_digits(std::string & s,std::istream & i,char & c,bool & ok,int base)85 __gmp_istream_set_digits (std::string &s, std::istream &i, char &c, bool &ok, int base)
86 {
87   switch (base)
88     {
89     case 10:
90       while (isdigit(c))
91         {
92           ok = true; // at least a valid digit was read
93           s += c;
94           if (! i.get(c))
95             break;
96         }
97       break;
98     case 8:
99       while (isdigit(c) && c != '8' && c != '9')
100         {
101           ok = true; // at least a valid digit was read
102           s += c;
103           if (! i.get(c))
104             break;
105         }
106       break;
107     case 16:
108       while (isxdigit(c))
109         {
110           ok = true; // at least a valid digit was read
111           s += c;
112           if (! i.get(c))
113             break;
114         }
115       break;
116     }
117 }
118 
119 CGAL_INLINE_FUNCTION
120 std::istream &
121 //operator>> (std::istream &i, mpz_ptr z)
io_read(std::istream & i,mpz_ptr z)122 io_read (std::istream &i, mpz_ptr z)
123 {
124   using namespace std;
125   int base;
126   char c = 0;
127   std::string s;
128   bool ok = false, zero, showbase;
129 
130   i.get(c); // start reading
131 
132   if (i.flags() & ios::skipws) // skip initial whitespace
133     while (isspace(c) && i.get(c))
134       ;
135 
136   if (c == '-' || c == '+') // sign
137     {
138       if (c == '-') // mpz_set_str doesn't accept '+'
139         s = "-";
140       i.get(c);
141     }
142 
143   while (isspace(c) && i.get(c)) // skip whitespace
144     ;
145 
146   base = __gmp_istream_set_base(i, c, zero, showbase); // select the base
147   __gmp_istream_set_digits(s, i, c, ok, base);         // read the number
148 
149   if (i.good()) // last character read was non-numeric
150     i.putback(c);
151   else if (i.eof() && (ok || zero)) // stopped just before eof
152     i.clear();
153 
154   if (ok)
155     mpz_set_str(z, s.c_str(), base); // extract the number
156   else if (zero)
157     mpz_set_ui(z, 0);
158   else
159     i.setstate(ios::failbit); // read failed
160 
161   return i;
162 }
163 
164 CGAL_INLINE_FUNCTION
165 std::istream &
166 //operator>> (std::istream &i, mpq_ptr q)
io_read(std::istream & i,mpq_ptr q)167 io_read (std::istream &i, mpq_ptr q)
168 {
169   using namespace std;
170   int base;
171   char c = 0;
172   std::string s;
173   bool ok = false, zero, showbase;
174 
175   i.get(c); // start reading
176 
177   if (i.flags() & ios::skipws) // skip initial whitespace
178     while (isspace(c) && i.get(c))
179       ;
180 
181   if (c == '-' || c == '+') // sign
182     {
183       if (c == '-')
184         s = "-";
185       i.get(c);
186     }
187 
188   while (isspace(c) && i.get(c)) // skip whitespace
189     ;
190 
191   base = __gmp_istream_set_base(i, c, zero, showbase); // select the base
192   __gmp_istream_set_digits(s, i, c, ok, base);         // read the numerator
193 
194   if (! ok && zero) // the only digit read was "0"
195     {
196       base = 10;
197       s += '0';
198       ok = true;
199     }
200 
201   if (c == '/') // there's a denominator
202     {
203       bool zero2 = false;
204       int base2 = base;
205 
206       s += '/';
207       ok = false; // denominator is mandatory
208       i.get(c);
209 
210       while (isspace(c) && i.get(c)) // skip whitespace
211         ;
212 
213       if (showbase) // check base of denominator
214         base2 = __gmp_istream_set_base(i, c, zero2, showbase);
215 
216       if (base2 == base || base2 == 10) // read the denominator
217         __gmp_istream_set_digits(s, i, c, ok, base);
218 
219       if (! ok && zero2) // the only digit read was "0"
220         {                // denominator is 0, but that's your business
221           s += '0';
222           ok = true;
223         }
224     }
225 
226   if (i.good()) // last character read was non-numeric
227     i.putback(c);
228   else if (i.eof() && ok) // stopped just before eof
229     i.clear();
230 
231   if (ok)
232     mpq_set_str(q, s.c_str(), base); // extract the number
233   else
234     i.setstate(ios::failbit); // read failed
235 
236   return i;
237 }
238 
239 CGAL_INLINE_FUNCTION
240 std::ostream&
241 //operator<< (std::ostream &o, mpz_srcptr z)
io_write(std::ostream & o,mpz_srcptr z)242 io_write (std::ostream &o, mpz_srcptr z)
243 {
244   char *str = new char [mpz_sizeinbase(z,10) + 2];
245   str = mpz_get_str(str, 10, z);
246   o << str ;
247   delete[] str;
248   return o;
249 }
250 
251 CGAL_INLINE_FUNCTION
252 std::ostream&
253 //operator<< (std::ostream &o, mpq_srcptr q)
io_write(std::ostream & o,mpq_srcptr q)254 io_write (std::ostream &o, mpq_srcptr q)
255 {
256   // size according to GMP documentation
257   char *str = new char [mpz_sizeinbase(mpq_numref(q), 10) +
258                         mpz_sizeinbase (mpq_denref(q), 10) + 3];
259   str = mpq_get_str(str, 10, q);
260   o << str ;
261   delete[] str;
262   return o;
263 }
264 
265 } //namespace CORE
266