Home | History | Annotate | Line # | Download | only in tests
      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