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