1 /* read_data.c -- Read data file and check function.
2
3 Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA
4
5 This file is part of GNU MPC.
6
7 GNU MPC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/ .
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "mpc-tests.h"
24
25 char *pathname;
26 unsigned long line_number;
27 /* file name with complete path and currently read line;
28 kept globally to simplify parameter passing */
29 unsigned long test_line_number;
30 /* start line of data test (which may extend over several lines) */
31 int nextchar;
32 /* character appearing next in the file, may be EOF */
33
34 #define MPC_INEX_CMP(r, i, c) \
35 (((r) == TERNARY_NOT_CHECKED || (r) == MPC_INEX_RE(c)) \
36 && ((i) == TERNARY_NOT_CHECKED || (i) == MPC_INEX_IM (c)))
37
38 #define MPFR_INEX_STR(inex) \
39 (inex) == TERNARY_NOT_CHECKED ? "?" \
40 : (inex) == +1 ? "+1" \
41 : (inex) == -1 ? "-1" : "0"
42
43 /* file functions */
44 FILE *
open_data_file(const char * file_name)45 open_data_file (const char *file_name)
46 {
47 FILE *fp;
48 char *src_dir;
49 char default_srcdir[] = ".";
50
51 src_dir = getenv ("srcdir");
52 if (src_dir == NULL)
53 src_dir = default_srcdir;
54
55 pathname = (char *) malloc ((strlen (src_dir)) + strlen (file_name) + 2);
56 if (pathname == NULL)
57 {
58 printf ("Cannot allocate memory\n");
59 exit (1);
60 }
61 sprintf (pathname, "%s/%s", src_dir, file_name);
62 fp = fopen (pathname, "r");
63 if (fp == NULL)
64 {
65 fprintf (stderr, "Unable to open %s\n", pathname);
66 exit (1);
67 }
68
69 return fp;
70 }
71
72 void
close_data_file(FILE * fp)73 close_data_file (FILE *fp)
74 {
75 free (pathname);
76 fclose (fp);
77 }
78
79 /* read primitives */
80 static void
skip_line(FILE * fp)81 skip_line (FILE *fp)
82 /* skips characters until reaching '\n' or EOF; */
83 /* '\n' is skipped as well */
84 {
85 while (nextchar != EOF && nextchar != '\n')
86 nextchar = getc (fp);
87 if (nextchar != EOF)
88 {
89 line_number ++;
90 nextchar = getc (fp);
91 }
92 }
93
94 static void
skip_whitespace(FILE * fp)95 skip_whitespace (FILE *fp)
96 /* skips over whitespace if any until reaching EOF */
97 /* or non-whitespace */
98 {
99 while (isspace (nextchar))
100 {
101 if (nextchar == '\n')
102 line_number ++;
103 nextchar = getc (fp);
104 }
105 }
106
107 void
skip_whitespace_comments(FILE * fp)108 skip_whitespace_comments (FILE *fp)
109 /* skips over all whitespace and comments, if any */
110 {
111 skip_whitespace (fp);
112 while (nextchar == '#') {
113 skip_line (fp);
114 if (nextchar != EOF)
115 skip_whitespace (fp);
116 }
117 }
118
119 size_t
read_string(FILE * fp,char ** buffer_ptr,size_t buffer_length,const char * name)120 read_string (FILE *fp, char **buffer_ptr, size_t buffer_length, const char *name)
121 {
122 size_t pos;
123 char *buffer;
124
125 pos = 0;
126 buffer = *buffer_ptr;
127
128 if (nextchar == '"')
129 nextchar = getc (fp);
130 else
131 goto error;
132
133 while (nextchar != EOF && nextchar != '"')
134 {
135 if (nextchar == '\n')
136 line_number ++;
137 if (pos + 1 > buffer_length)
138 {
139 buffer = (char *) realloc (buffer, 2 * buffer_length);
140 if (buffer == NULL)
141 {
142 printf ("Cannot allocate memory\n");
143 exit (1);
144 }
145 buffer_length *= 2;
146 }
147 buffer[pos++] = (char) nextchar;
148 nextchar = getc (fp);
149 }
150
151 if (nextchar != '"')
152 goto error;
153
154 if (pos + 1 > buffer_length)
155 {
156 buffer = (char *) realloc (buffer, buffer_length + 1);
157 if (buffer == NULL)
158 {
159 printf ("Cannot allocate memory\n");
160 exit (1);
161 }
162 buffer_length *= 2;
163 }
164 buffer[pos] = '\0';
165
166 nextchar = getc (fp);
167 skip_whitespace_comments (fp);
168
169 *buffer_ptr = buffer;
170
171 return buffer_length;
172
173 error:
174 printf ("Error: Unable to read %s in file '%s' line '%lu'\n",
175 name, pathname, line_number);
176 exit (1);
177 }
178
179 /* All following read routines skip over whitespace and comments; */
180 /* so after calling them, nextchar is either EOF or the beginning */
181 /* of a non-comment token. */
182 void
read_ternary(FILE * fp,int * ternary)183 read_ternary (FILE *fp, int* ternary)
184 {
185 switch (nextchar)
186 {
187 case '!':
188 *ternary = TERNARY_ERROR;
189 break;
190 case '?':
191 *ternary = TERNARY_NOT_CHECKED;
192 break;
193 case '+':
194 *ternary = +1;
195 break;
196 case '0':
197 *ternary = 0;
198 break;
199 case '-':
200 *ternary = -1;
201 break;
202 default:
203 printf ("Error: Unexpected ternary value '%c' in file '%s' line %lu\n",
204 nextchar, pathname, line_number);
205 exit (1);
206 }
207
208 nextchar = getc (fp);
209 skip_whitespace_comments (fp);
210 }
211
212 void
read_mpfr_rounding_mode(FILE * fp,mpfr_rnd_t * rnd)213 read_mpfr_rounding_mode (FILE *fp, mpfr_rnd_t* rnd)
214 {
215 switch (nextchar)
216 {
217 case 'n': case 'N':
218 *rnd = MPFR_RNDN;
219 break;
220 case 'z': case 'Z':
221 *rnd = MPFR_RNDZ;
222 break;
223 case 'u': case 'U':
224 *rnd = MPFR_RNDU;
225 break;
226 case 'd': case 'D':
227 *rnd = MPFR_RNDD;
228 break;
229 default:
230 printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
231 nextchar, pathname, line_number);
232 exit (1);
233 }
234
235 nextchar = getc (fp);
236 if (nextchar != EOF && !isspace (nextchar)) {
237 printf ("Error: Rounding mode not followed by white space in file "
238 "'%s' line %lu\n",
239 pathname, line_number);
240 exit (1);
241 }
242 skip_whitespace_comments (fp);
243 }
244
245 void
read_mpc_rounding_mode(FILE * fp,mpc_rnd_t * rnd)246 read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
247 {
248 mpfr_rnd_t re, im;
249 read_mpfr_rounding_mode (fp, &re);
250 read_mpfr_rounding_mode (fp, &im);
251 *rnd = MPC_RND (re, im);
252 }
253
254 void
read_int(FILE * fp,int * nread,const char * name)255 read_int (FILE *fp, int *nread, const char *name)
256 {
257 int n = 0;
258
259 if (nextchar == EOF)
260 {
261 printf ("Error: Unexpected EOF when reading int "
262 "in file '%s' line %lu\n",
263 pathname, line_number);
264 exit (1);
265 }
266 ungetc (nextchar, fp);
267 n = fscanf (fp, "%i", nread);
268 if (ferror (fp) || n == 0 || n == EOF)
269 {
270 printf ("Error: Cannot read %s in file '%s' line %lu\n",
271 name, pathname, line_number);
272 exit (1);
273 }
274 nextchar = getc (fp);
275 skip_whitespace_comments (fp);
276 }
277
278 mpfr_prec_t
read_mpfr_prec(FILE * fp)279 read_mpfr_prec (FILE *fp)
280 {
281 unsigned long prec;
282 int n;
283
284 if (nextchar == EOF) {
285 printf ("Error: Unexpected EOF when reading mpfr precision "
286 "in file '%s' line %lu\n",
287 pathname, line_number);
288 exit (1);
289 }
290 ungetc (nextchar, fp);
291 n = fscanf (fp, "%lu", &prec);
292 if (ferror (fp)) /* then also n == EOF */
293 perror ("Error when reading mpfr precision");
294 if (n == 0 || n == EOF || prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
295 printf ("Error: Impossible mpfr precision in file '%s' line %lu\n",
296 pathname, line_number);
297 exit (1);
298 }
299 nextchar = getc (fp);
300 skip_whitespace_comments (fp);
301 return (mpfr_prec_t) prec;
302 }
303
304 static void
read_mpfr_mantissa(FILE * fp,mpfr_ptr x)305 read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
306 {
307 if (nextchar == EOF) {
308 printf ("Error: Unexpected EOF when reading mpfr mantissa "
309 "in file '%s' line %lu\n",
310 pathname, line_number);
311 exit (1);
312 }
313 ungetc (nextchar, fp);
314 if (mpfr_inp_str (x, fp, 0, MPFR_RNDN) == 0) {
315 printf ("Error: Impossible to read mpfr mantissa "
316 "in file '%s' line %lu\n",
317 pathname, line_number);
318 exit (1);
319 }
320 nextchar = getc (fp);
321 skip_whitespace_comments (fp);
322 }
323
324 void
read_mpfr(FILE * fp,mpfr_ptr x,int * known_sign)325 read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
326 {
327 int sign;
328 mpfr_set_prec (x, read_mpfr_prec (fp));
329 sign = nextchar;
330 read_mpfr_mantissa (fp, x);
331
332 /* the sign always matters for regular values ('+' is implicit),
333 but when no sign appears before 0 or Inf in the data file, it means
334 that only absolute value must be checked. */
335 if (known_sign != NULL)
336 *known_sign =
337 (!mpfr_zero_p (x) && !mpfr_inf_p (x))
338 || sign == '+' || sign == '-';
339 }
340
341 void
read_mpc(FILE * fp,mpc_ptr z,known_signs_t * ks)342 read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
343 {
344 read_mpfr (fp, mpc_realref (z), ks == NULL ? NULL : &ks->re);
345 read_mpfr (fp, mpc_imagref (z), ks == NULL ? NULL : &ks->im);
346 }
347