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 * 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 73 close_data_file (FILE *fp) 74 { 75 free (pathname); 76 fclose (fp); 77 } 78 79 /* read primitives */ 80 static void 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 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 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 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 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 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 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 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 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 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 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 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