OSDN Git Service

PR 48296 Accept EOF as separator when reading string with list format.
[pf3gnuchains/gcc-fork.git] / libgfortran / io / write_float.def
index 02e1b8b..b72cf9f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Contributed by Andy Vaught
    Write float code factoring to this file by Jerry DeLisle   
    F2003 I/O support contributed by Jerry DeLisle
@@ -61,7 +61,7 @@ calculate_sign (st_parameter_dt *dtp, int negative_flag)
 
 /* Output a real number according to its format which is FMT_G free.  */
 
-static void
+static try
 output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size, 
              int sign_bit, bool zero_flag, int ndigits, int edigits)
 {
@@ -109,37 +109,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 
   /* Make sure zero comes out as 0.0e0.   */
   if (zero_flag)
-    {
-      e = 0;
-      if (compile_options.sign_zero == 1)
-       sign = calculate_sign (dtp, sign_bit);
-      else
-       sign = calculate_sign (dtp, 0);
-
-      /* Handle special cases.  */
-      if (w == 0)
-       w = d + 2;
-
-      /* For this one we choose to not output a decimal point.
-        F95 10.5.1.2.1  */
-      if (w == 1 && ft == FMT_F)
-       {
-         out = write_block (dtp, w);
-         if (out == NULL)
-           return;
-
-         if (unlikely (is_char4_unit (dtp)))
-           {
-             gfc_char4_t *out4 = (gfc_char4_t *) out;
-             *out4 = '0';
-             return;
-           }
-
-         *out = '0';
-         return;
-       }
-             
-    }
+    e = 0;
 
   /* Normalize the fractional component.  */
   buffer[2] = buffer[1];
@@ -181,13 +151,13 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
        {
          generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
                          "greater than zero in format specifier 'E' or 'D'");
-         return;
+         return FAILURE;
        }
       if (i <= -d || i >= d + 2)
        {
          generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
                          "out of range in format specifier 'E' or 'D'");
-         return;
+         return FAILURE;
        }
 
       if (!zero_flag)
@@ -398,15 +368,21 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
   else
     edigits = 0;
 
-  /* Zero values always output as positive, even if the value was negative
-     before rounding.  */
+  /* Scan the digits string and count the number of zeros.  If we make it
+     all the way through the loop, we know the value is zero after the
+     rounding completed above.  */
   for (i = 0; i < ndigits; i++)
     {
       if (digits[i] != '0')
        break;
     }
+
+  /* To format properly, we need to know if the rounded result is zero and if
+     so, we set the zero_flag which may have been already set for
+     actual zero.  */
   if (i == ndigits)
     {
+      zero_flag = true;
       /* The output is zero, so set the sign according to the sign bit unless
         -fno-sign-zero was specified.  */
       if (compile_options.sign_zero == 1)
@@ -415,9 +391,18 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
        sign = calculate_sign (dtp, 0);
     }
 
-  /* Pick a field size if none was specified.  */
+  /* Pick a field size if none was specified, taking into account small
+     values that may have been rounded to zero.  */
   if (w <= 0)
-    w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
+    {
+      if (zero_flag)
+       w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
+      else
+       {
+         w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
+         w = w == 1 ? 2 : w;
+       }
+    }
   
   /* Work out how much padding is needed.  */
   nblanks = w - (nbefore + nzero + nafter + edigits + 1);
@@ -433,18 +418,19 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
   /* Create the ouput buffer.  */
   out = write_block (dtp, w);
   if (out == NULL)
-    return;
+    return FAILURE;
 
   /* Check the value fits in the specified field width.  */
-  if (nblanks < 0 || edigits == -1)
+  if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
     {
       if (unlikely (is_char4_unit (dtp)))
        {
-         memset4 (out, 0, '*', w);
-         return;
+         gfc_char4_t *out4 = (gfc_char4_t *) out;
+         memset4 (out4, '*', w);
+         return FAILURE;
        }
       star_fill (out, w);
-      return;
+      return FAILURE;
     }
 
   /* See if we have space for a zero before the decimal point.  */
@@ -466,7 +452,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 
       if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
        {
-         memset4 (out, 0, ' ', nblanks);
+         memset4 (out4, ' ', nblanks);
          out4 += nblanks;
        }
 
@@ -486,7 +472,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
          if (nbefore > ndigits)
            {
              i = ndigits;
-             memcpy4 (out4, 0, digits, i);
+             memcpy4 (out4, digits, i);
              ndigits = 0;
              while (i < nbefore)
                out4[i++] = '0';
@@ -494,7 +480,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
          else
            {
              i = nbefore;
-             memcpy4 (out4, 0, digits, i);
+             memcpy4 (out4, digits, i);
              ndigits -= i;
            }
 
@@ -521,7 +507,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
          else
            i = nafter;
 
-         memcpy4 (out4, 0, digits, i);
+         memcpy4 (out4, digits, i);
          while (i < nafter)
            out4[i++] = '0';
 
@@ -543,16 +529,16 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 #else
          sprintf (buffer, "%+0*d", edigits, e);
 #endif
-         memcpy4 (out4, 0, buffer, edigits);
+         memcpy4 (out4, buffer, edigits);
        }
 
       if (dtp->u.p.no_leading_blank)
        {
          out4 += edigits;
-         memset4 (out4 , 0, ' ' , nblanks);
+         memset4 (out4, ' ' , nblanks);
          dtp->u.p.no_leading_blank = 0;
        }
-      return;
+      return SUCCESS;
     } /* End of character(kind=4) internal unit code.  */
 
   /* Pad to full field width.  */
@@ -648,6 +634,7 @@ output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 #undef STR
 #undef STR1
 #undef MIN_FIELD_WIDTH
+  return SUCCESS;
 }
 
 
@@ -658,29 +645,46 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
 {
   char * p, fin;
   int nb = 0;
+  sign_t sign;
+  int mark;
 
   if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
     {
+      sign = calculate_sign (dtp, sign_bit);
+      mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
+
       nb =  f->u.real.w;
   
       /* If the field width is zero, the processor must select a width 
         not zero.  4 is chosen to allow output of '-Inf' or '+Inf' */
      
-      if (nb == 0) nb = 4;
+      if (nb == 0)
+       {
+         if (isnan_flag)
+           nb = 3;
+         else
+           nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
+       }
       p = write_block (dtp, nb);
       if (p == NULL)
        return;
       if (nb < 3)
        {
          if (unlikely (is_char4_unit (dtp)))
-           memset4 (p, 0, '*', nb);
+           {
+             gfc_char4_t *p4 = (gfc_char4_t *) p;
+             memset4 (p4, '*', nb);
+           }
          else
            memset (p, '*', nb);
          return;
        }
 
       if (unlikely (is_char4_unit (dtp)))
-        memset4 (p, 0, ' ', nb);
+       {
+         gfc_char4_t *p4 = (gfc_char4_t *) p;
+         memset4 (p4, ' ', nb);
+       }
       else
        memset(p, ' ', nb);
 
@@ -693,7 +697,10 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
              if (nb == 3)
                {
                  if (unlikely (is_char4_unit (dtp)))
-                   memset4 (p, 0, '*', nb);
+                   {
+                     gfc_char4_t *p4 = (gfc_char4_t *) p;
+                     memset4 (p4, '*', nb);
+                   }
                  else
                    memset (p, '*', nb);
                  return;
@@ -709,24 +716,28 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
          if (unlikely (is_char4_unit (dtp)))
            {
              gfc_char4_t *p4 = (gfc_char4_t *) p;
-             if (nb > 8)
+
+             if (nb > mark)
                /* We have room, so output 'Infinity' */
-               memcpy4 (p4, nb - 8, "Infinity", 8);
+               memcpy4 (p4 + nb - 8, "Infinity", 8);
              else
-               /* For the case of width equals 8, there is not enough room
+               /* For the case of width equals mark, there is not enough room
                   for the sign and 'Infinity' so we go with 'Inf' */
-               memcpy4 (p4, nb - 3, "Inf", 3);
+               memcpy4 (p4 + nb - 3, "Inf", 3);
 
-             if (nb < 9 && nb > 3)
-               /* Put the sign in front of Inf */
-               p4[nb - 4] = (gfc_char4_t) fin;
-             else if (nb > 8)
-               /* Put the sign in front of Infinity */
-               p4[nb - 9] = (gfc_char4_t) fin;
+             if (sign == S_PLUS || sign == S_MINUS)
+               {
+                 if (nb < 9 && nb > 3)
+                   /* Put the sign in front of Inf */
+                   p4[nb - 4] = (gfc_char4_t) fin;
+                 else if (nb > 8)
+                   /* Put the sign in front of Infinity */
+                   p4[nb - 9] = (gfc_char4_t) fin;
+               }
              return;
            }
 
-         if (nb > 8)
+         if (nb > mark)
            /* We have room, so output 'Infinity' */
            memcpy(p + nb - 8, "Infinity", 8);
          else
@@ -734,15 +745,21 @@ write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit
               for the sign and 'Infinity' so we go with 'Inf' */
            memcpy(p + nb - 3, "Inf", 3);
 
-         if (nb < 9 && nb > 3)
-           p[nb - 4] = fin;  /* Put the sign in front of Inf */
-         else if (nb > 8)
-           p[nb - 9] = fin;  /* Put the sign in front of Infinity */
+         if (sign == S_PLUS || sign == S_MINUS)
+           {
+             if (nb < 9 && nb > 3)
+               p[nb - 4] = fin;  /* Put the sign in front of Inf */
+             else if (nb > 8)
+               p[nb - 9] = fin;  /* Put the sign in front of Infinity */
+           }
        }
       else
         {
          if (unlikely (is_char4_unit (dtp)))
-           memcpy4 (p, nb - 3, "NaN", 3);
+           {
+             gfc_char4_t *p4 = (gfc_char4_t *) p;
+             memcpy4 (p4 + nb - 3, "NaN", 3);
+           }
          else
            memcpy(p + nb - 3, "NaN", 3);
        }
@@ -808,8 +825,9 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
   GFC_REAL_ ## x rexp_d;\
   int low, high, mid;\
   int ubound, lbound;\
-  char *p;\
+  char *p, pad = ' ';\
   int save_scale_factor, nb = 0;\
+  try result;\
 \
   save_scale_factor = dtp->u.p.scale_factor;\
   newf = (fnode *) get_mem (sizeof (fnode));\
@@ -863,11 +881,14 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
        }\
     }\
 \
+  if (e > 4)\
+    e = 4;\
   if (e < 0)\
     nb = 4;\
   else\
     nb = e + 2;\
 \
+  nb = nb >= w ? 0 : nb;\
   newf->format = FMT_F;\
   newf->u.real.w = f->u.real.w - nb;\
 \
@@ -879,21 +900,26 @@ output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
   dtp->u.p.scale_factor = 0;\
 \
  finish:\
-  output_float (dtp, newf, buffer, size, sign_bit, zero_flag, ndigits, \
-               edigits);\
+  result = output_float (dtp, newf, buffer, size, sign_bit, zero_flag, \
+                        ndigits, edigits);\
   dtp->u.p.scale_factor = save_scale_factor;\
 \
   free (newf);\
 \
   if (nb > 0 && !dtp->u.p.g0_no_blanks)\
-    { \
+    {\
       p = write_block (dtp, nb);\
       if (p == NULL)\
        return;\
+      if (result == FAILURE)\
+        pad = '*';\
       if (unlikely (is_char4_unit (dtp)))\
-       memset4 (p, 0, ' ', nb);\
+       {\
+         gfc_char4_t *p4 = (gfc_char4_t *) p;\
+         memset4 (p4, pad, nb);\
+       }\
       else\
-       memset (p, ' ', nb);\
+       memset (p, pad, nb);\
     }\
 }\
 
@@ -957,11 +983,18 @@ sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
 
 #endif
 
+#if defined(GFC_REAL_16_IS_FLOAT128)
+#define DTOAQ \
+__qmath_(quadmath_snprintf) (buffer, sizeof buffer, \
+                            "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
+                            "Qe", ndigits - 1, tmp);
+#endif
+
 #define WRITE_FLOAT(x,y)\
 {\
        GFC_REAL_ ## x tmp;\
        tmp = * (GFC_REAL_ ## x *)source;\
-       sign_bit = __builtin_signbit (tmp);\
+       sign_bit = signbit (tmp);\
        if (!isfinite (tmp))\
          { \
            write_infnan (dtp, f, isnan (tmp), sign_bit);\
@@ -986,8 +1019,8 @@ static void
 write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
 {
 
-#if defined(HAVE_GFC_REAL_16) && __LDBL_DIG__ > 18
-# define MIN_FIELD_WIDTH 46
+#if defined(HAVE_GFC_REAL_16) || __LDBL_DIG__ > 18
+# define MIN_FIELD_WIDTH 48
 #else
 # define MIN_FIELD_WIDTH 31
 #endif
@@ -1041,7 +1074,11 @@ write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
 #endif
 #ifdef HAVE_GFC_REAL_16
     case 16:
+# ifdef GFC_REAL_16_IS_FLOAT128
+      WRITE_FLOAT(16,Q)
+# else
       WRITE_FLOAT(16,L)
+# endif
       break;
 #endif
     default: