xref: /netbsd-src/external/lgpl3/mpc/dist/tests/read_data.c (revision 367b82799ab709709d3c3b541df56a2a14644d3e)
1 /* read_data.c -- Read data file and check function.
2 
3 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2022 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     case 'a': case 'A':
230       *rnd = MPFR_RNDA;
231       break;
232     default:
233       printf ("Error: Unexpected rounding mode '%c' in file '%s' line %lu\n",
234               nextchar, pathname, line_number);
235       exit (1);
236     }
237 
238     nextchar = getc (fp);
239     if (nextchar != EOF && !isspace (nextchar)) {
240       printf ("Error: Rounding mode not followed by white space in file "
241               "'%s' line %lu\n",
242               pathname, line_number);
243       exit (1);
244     }
245     skip_whitespace_comments (fp);
246 }
247 
248 void
read_mpc_rounding_mode(FILE * fp,mpc_rnd_t * rnd)249 read_mpc_rounding_mode (FILE *fp, mpc_rnd_t* rnd)
250 {
251    mpfr_rnd_t re, im;
252    read_mpfr_rounding_mode (fp, &re);
253    read_mpfr_rounding_mode (fp, &im);
254    *rnd = MPC_RND (re, im);
255 }
256 
257 void
read_int(FILE * fp,int * nread,const char * name)258 read_int (FILE *fp, int *nread, const char *name)
259 {
260   int n = 0;
261 
262   if (nextchar == EOF)
263     {
264       printf ("Error: Unexpected EOF when reading int "
265               "in file '%s' line %lu\n",
266               pathname, line_number);
267       exit (1);
268     }
269   ungetc (nextchar, fp);
270   n = fscanf (fp, "%i", nread);
271   if (ferror (fp) || n == 0 || n == EOF)
272     {
273       printf ("Error: Cannot read %s in file '%s' line %lu\n",
274               name, pathname, line_number);
275       exit (1);
276     }
277   nextchar = getc (fp);
278   skip_whitespace_comments (fp);
279 }
280 
281 mpfr_prec_t
read_mpfr_prec(FILE * fp)282 read_mpfr_prec (FILE *fp)
283 {
284    unsigned long prec;
285    int n;
286 
287    if (nextchar == EOF) {
288       printf ("Error: Unexpected EOF when reading mpfr precision "
289               "in file '%s' line %lu\n",
290               pathname, line_number);
291       exit (1);
292    }
293    ungetc (nextchar, fp);
294    n = fscanf (fp, "%lu", &prec);
295    if (ferror (fp)) /* then also n == EOF */
296       perror ("Error when reading mpfr precision");
297    if (n == 0 || n == EOF || prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
298       printf ("Error: Impossible mpfr precision in file '%s' line %lu\n",
299               pathname, line_number);
300       exit (1);
301    }
302    nextchar = getc (fp);
303    skip_whitespace_comments (fp);
304    return (mpfr_prec_t) prec;
305 }
306 
307 static void
read_mpfr_mantissa(FILE * fp,mpfr_ptr x)308 read_mpfr_mantissa (FILE *fp, mpfr_ptr x)
309 {
310    if (nextchar == EOF) {
311       printf ("Error: Unexpected EOF when reading mpfr mantissa "
312               "in file '%s' line %lu\n",
313               pathname, line_number);
314       exit (1);
315    }
316    ungetc (nextchar, fp);
317    if (mpfr_inp_str (x, fp, 0, MPFR_RNDN) == 0) {
318       printf ("Error: Impossible to read mpfr mantissa "
319               "in file '%s' line %lu\n",
320               pathname, line_number);
321       exit (1);
322    }
323    nextchar = getc (fp);
324    skip_whitespace_comments (fp);
325 }
326 
327 void
read_mpfr(FILE * fp,mpfr_ptr x,int * known_sign)328 read_mpfr (FILE *fp, mpfr_ptr x, int *known_sign)
329 {
330    int sign;
331    mpfr_set_prec (x, read_mpfr_prec (fp));
332    sign = nextchar;
333    read_mpfr_mantissa (fp, x);
334 
335    /* the sign always matters for regular values ('+' is implicit),
336       but when no sign appears before 0 or Inf in the data file, it means
337       that only absolute value must be checked. */
338    if (known_sign != NULL)
339      *known_sign =
340        (!mpfr_zero_p (x) && !mpfr_inf_p (x))
341        || sign == '+' || sign == '-';
342 }
343 
344 void
read_mpc(FILE * fp,mpc_ptr z,known_signs_t * ks)345 read_mpc (FILE *fp, mpc_ptr z, known_signs_t *ks)
346 {
347   read_mpfr (fp, mpc_realref (z), ks == NULL ? NULL : &ks->re);
348   read_mpfr (fp, mpc_imagref (z), ks == NULL ? NULL : &ks->im);
349 }
350