mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1330 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
			
		
		
	
	
			1330 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
/* Copyright (C) 2007-2015 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
 | 
						|
 | 
						|
This file is part of the GNU Fortran runtime library (libgfortran).
 | 
						|
 | 
						|
Libgfortran is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 3, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
Libgfortran is distributed in the hope that it will be useful,
 | 
						|
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
GNU General Public License for more details.
 | 
						|
 | 
						|
Under Section 7 of GPL version 3, you are granted additional
 | 
						|
permissions described in the GCC Runtime Library Exception, version
 | 
						|
3.1, as published by the Free Software Foundation.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License and
 | 
						|
a copy of the GCC Runtime Library Exception along with this program;
 | 
						|
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | 
						|
<http://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
typedef enum
 | 
						|
{ S_NONE, S_MINUS, S_PLUS }
 | 
						|
sign_t;
 | 
						|
 | 
						|
/* Given a flag that indicates if a value is negative or not, return a
 | 
						|
   sign_t that gives the sign that we need to produce.  */
 | 
						|
 | 
						|
static sign_t
 | 
						|
calculate_sign (st_parameter_dt *dtp, int negative_flag)
 | 
						|
{
 | 
						|
  sign_t s = S_NONE;
 | 
						|
 | 
						|
  if (negative_flag)
 | 
						|
    s = S_MINUS;
 | 
						|
  else
 | 
						|
    switch (dtp->u.p.sign_status)
 | 
						|
      {
 | 
						|
      case SIGN_SP:	/* Show sign. */
 | 
						|
	s = S_PLUS;
 | 
						|
	break;
 | 
						|
      case SIGN_SS:	/* Suppress sign. */
 | 
						|
	s = S_NONE;
 | 
						|
	break;
 | 
						|
      case SIGN_S:	/* Processor defined. */
 | 
						|
      case SIGN_UNSPECIFIED:
 | 
						|
	s = options.optional_plus ? S_PLUS : S_NONE;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
 | 
						|
  return s;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Determine the precision except for EN format. For G format,
 | 
						|
   determines an upper bound to be used for sizing the buffer. */
 | 
						|
 | 
						|
static int
 | 
						|
determine_precision (st_parameter_dt * dtp, const fnode * f, int len)
 | 
						|
{
 | 
						|
  int precision = f->u.real.d;
 | 
						|
 | 
						|
  switch (f->format)
 | 
						|
    {
 | 
						|
    case FMT_F:
 | 
						|
    case FMT_G:
 | 
						|
      precision += dtp->u.p.scale_factor;
 | 
						|
      break;
 | 
						|
    case FMT_ES:
 | 
						|
      /* Scale factor has no effect on output.  */
 | 
						|
      break;
 | 
						|
    case FMT_E:
 | 
						|
    case FMT_D:
 | 
						|
      /* See F2008 10.7.2.3.3.6 */
 | 
						|
      if (dtp->u.p.scale_factor <= 0)
 | 
						|
	precision += dtp->u.p.scale_factor - 1;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* If the scale factor has a large negative value, we must do our
 | 
						|
     own rounding? Use ROUND='NEAREST', which should be what snprintf
 | 
						|
     is using as well.  */
 | 
						|
  if (precision < 0 && 
 | 
						|
      (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED 
 | 
						|
       || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
 | 
						|
    dtp->u.p.current_unit->round_status = ROUND_NEAREST;
 | 
						|
 | 
						|
  /* Add extra guard digits up to at least full precision when we do
 | 
						|
     our own rounding.  */
 | 
						|
  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
 | 
						|
      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
 | 
						|
    {
 | 
						|
      precision += 2 * len + 4;
 | 
						|
      if (precision < 0)
 | 
						|
	precision = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  return precision;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Output a real number according to its format which is FMT_G free.  */
 | 
						|
 | 
						|
static bool
 | 
						|
output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 | 
						|
	      int nprinted, int precision, int sign_bit, bool zero_flag)
 | 
						|
{
 | 
						|
  char *out;
 | 
						|
  char *digits;
 | 
						|
  int e, w, d, p, i;
 | 
						|
  char expchar, rchar;
 | 
						|
  format_token ft;
 | 
						|
  /* Number of digits before the decimal point.  */
 | 
						|
  int nbefore;
 | 
						|
  /* Number of zeros after the decimal point.  */
 | 
						|
  int nzero;
 | 
						|
  /* Number of digits after the decimal point.  */
 | 
						|
  int nafter;
 | 
						|
  int leadzero;
 | 
						|
  int nblanks;
 | 
						|
  int ndigits, edigits;
 | 
						|
  sign_t sign;
 | 
						|
 | 
						|
  ft = f->format;
 | 
						|
  w = f->u.real.w;
 | 
						|
  d = f->u.real.d;
 | 
						|
  p = dtp->u.p.scale_factor;
 | 
						|
 | 
						|
  rchar = '5';
 | 
						|
 | 
						|
  /* We should always know the field width and precision.  */
 | 
						|
  if (d < 0)
 | 
						|
    internal_error (&dtp->common, "Unspecified precision");
 | 
						|
 | 
						|
  sign = calculate_sign (dtp, sign_bit);
 | 
						|
  
 | 
						|
  /* Calculate total number of digits.  */
 | 
						|
  if (ft == FMT_F)
 | 
						|
    ndigits = nprinted - 2;
 | 
						|
  else
 | 
						|
    ndigits = precision + 1;
 | 
						|
 | 
						|
  /* Read the exponent back in.  */
 | 
						|
  if (ft != FMT_F)
 | 
						|
    e = atoi (&buffer[ndigits + 3]) + 1;
 | 
						|
  else
 | 
						|
    e = 0;
 | 
						|
 | 
						|
  /* Make sure zero comes out as 0.0e0.   */
 | 
						|
  if (zero_flag)
 | 
						|
    e = 0;
 | 
						|
 | 
						|
  /* Normalize the fractional component.  */
 | 
						|
  if (ft != FMT_F)
 | 
						|
    {
 | 
						|
      buffer[2] = buffer[1];
 | 
						|
      digits = &buffer[2];
 | 
						|
    }
 | 
						|
  else
 | 
						|
    digits = &buffer[1];
 | 
						|
 | 
						|
  /* Figure out where to place the decimal point.  */
 | 
						|
  switch (ft)
 | 
						|
    {
 | 
						|
    case FMT_F:
 | 
						|
      nbefore = ndigits - precision;
 | 
						|
      /* Make sure the decimal point is a '.'; depending on the
 | 
						|
	 locale, this might not be the case otherwise.  */
 | 
						|
      digits[nbefore] = '.';
 | 
						|
      if (p != 0)
 | 
						|
	{
 | 
						|
	  if (p > 0)
 | 
						|
	    {
 | 
						|
	      
 | 
						|
	      memmove (digits + nbefore, digits + nbefore + 1, p);
 | 
						|
	      digits[nbefore + p] = '.';
 | 
						|
	      nbefore += p;
 | 
						|
	      nafter = d;
 | 
						|
	      nzero = 0;
 | 
						|
	    }
 | 
						|
	  else /* p < 0  */
 | 
						|
	    {
 | 
						|
	      if (nbefore + p >= 0)
 | 
						|
		{
 | 
						|
		  nzero = 0;
 | 
						|
		  memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
 | 
						|
		  nbefore += p;
 | 
						|
		  digits[nbefore] = '.';
 | 
						|
		  nafter = d;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  nzero = -(nbefore + p);
 | 
						|
		  memmove (digits + 1, digits, nbefore);
 | 
						|
		  nafter = d - nzero;
 | 
						|
		  if (nafter == 0 && d > 0)
 | 
						|
		    {
 | 
						|
		      /* This is needed to get the correct rounding. */
 | 
						|
		      memmove (digits + 1, digits, ndigits - 1);
 | 
						|
		      digits[1] = '0';
 | 
						|
		      nafter = 1;
 | 
						|
		      nzero = d - 1;
 | 
						|
		    }
 | 
						|
		  else if (nafter < 0)
 | 
						|
		    {
 | 
						|
		      /* Reset digits to 0 in order to get correct rounding
 | 
						|
			 towards infinity. */
 | 
						|
		      for (i = 0; i < ndigits; i++)
 | 
						|
			digits[i] = '0';
 | 
						|
		      digits[ndigits - 1] = '1';
 | 
						|
		      nafter = d;
 | 
						|
		      nzero = 0;
 | 
						|
		    }
 | 
						|
		  nbefore = 0;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  nzero = 0;
 | 
						|
	  nafter = d;
 | 
						|
	}
 | 
						|
 | 
						|
      while (digits[0] == '0' && nbefore > 0)
 | 
						|
	{
 | 
						|
	  digits++;
 | 
						|
	  nbefore--;
 | 
						|
	  ndigits--;
 | 
						|
	}
 | 
						|
 | 
						|
      expchar = 0;
 | 
						|
      /* If we need to do rounding ourselves, get rid of the dot by
 | 
						|
	 moving the fractional part.  */
 | 
						|
      if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
 | 
						|
	  && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
 | 
						|
	memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
 | 
						|
      break;
 | 
						|
 | 
						|
    case FMT_E:
 | 
						|
    case FMT_D:
 | 
						|
      i = dtp->u.p.scale_factor;
 | 
						|
      if (d <= 0 && p == 0)
 | 
						|
	{
 | 
						|
	  generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
 | 
						|
			  "greater than zero in format specifier 'E' or 'D'");
 | 
						|
	  return false;
 | 
						|
	}
 | 
						|
      if (p <= -d || p >= d + 2)
 | 
						|
	{
 | 
						|
	  generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
 | 
						|
			  "out of range in format specifier 'E' or 'D'");
 | 
						|
	  return false;
 | 
						|
	}
 | 
						|
 | 
						|
      if (!zero_flag)
 | 
						|
	e -= p;
 | 
						|
      if (p < 0)
 | 
						|
	{
 | 
						|
	  nbefore = 0;
 | 
						|
	  nzero = -p;
 | 
						|
	  nafter = d + p;
 | 
						|
	}
 | 
						|
      else if (p > 0)
 | 
						|
	{
 | 
						|
	  nbefore = p;
 | 
						|
	  nzero = 0;
 | 
						|
	  nafter = (d - p) + 1;
 | 
						|
	}
 | 
						|
      else /* p == 0 */
 | 
						|
	{
 | 
						|
	  nbefore = 0;
 | 
						|
	  nzero = 0;
 | 
						|
	  nafter = d;
 | 
						|
	}
 | 
						|
 | 
						|
      if (ft == FMT_E)
 | 
						|
	expchar = 'E';
 | 
						|
      else
 | 
						|
	expchar = 'D';
 | 
						|
      break;
 | 
						|
 | 
						|
    case FMT_EN:
 | 
						|
      /* The exponent must be a multiple of three, with 1-3 digits before
 | 
						|
	 the decimal point.  */
 | 
						|
      if (!zero_flag)
 | 
						|
        e--;
 | 
						|
      if (e >= 0)
 | 
						|
	nbefore = e % 3;
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  nbefore = (-e) % 3;
 | 
						|
	  if (nbefore != 0)
 | 
						|
	    nbefore = 3 - nbefore;
 | 
						|
	}
 | 
						|
      e -= nbefore;
 | 
						|
      nbefore++;
 | 
						|
      nzero = 0;
 | 
						|
      nafter = d;
 | 
						|
      expchar = 'E';
 | 
						|
      break;
 | 
						|
 | 
						|
    case FMT_ES:
 | 
						|
      if (!zero_flag)
 | 
						|
        e--;
 | 
						|
      nbefore = 1;
 | 
						|
      nzero = 0;
 | 
						|
      nafter = d;
 | 
						|
      expchar = 'E';
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      /* Should never happen.  */
 | 
						|
      internal_error (&dtp->common, "Unexpected format token");
 | 
						|
    }
 | 
						|
 | 
						|
  if (zero_flag)
 | 
						|
    goto skip;
 | 
						|
 | 
						|
  /* Round the value.  The value being rounded is an unsigned magnitude.  */
 | 
						|
  switch (dtp->u.p.current_unit->round_status)
 | 
						|
    {
 | 
						|
      /* For processor defined and unspecified rounding we use
 | 
						|
	 snprintf to print the exact number of digits needed, and thus
 | 
						|
	 let snprintf handle the rounding.  On system claiming support
 | 
						|
	 for IEEE 754, this ought to be round to nearest, ties to
 | 
						|
	 even, corresponding to the Fortran ROUND='NEAREST'.  */
 | 
						|
      case ROUND_PROCDEFINED: 
 | 
						|
      case ROUND_UNSPECIFIED:
 | 
						|
      case ROUND_ZERO: /* Do nothing and truncation occurs.  */
 | 
						|
	goto skip;
 | 
						|
      case ROUND_UP:
 | 
						|
	if (sign_bit)
 | 
						|
	  goto skip;
 | 
						|
	goto updown;
 | 
						|
      case ROUND_DOWN:
 | 
						|
	if (!sign_bit)
 | 
						|
	  goto skip;
 | 
						|
	goto updown;
 | 
						|
      case ROUND_NEAREST:
 | 
						|
	/* Round compatible unless there is a tie. A tie is a 5 with
 | 
						|
	   all trailing zero's.  */
 | 
						|
	i = nafter + nbefore;
 | 
						|
	if (digits[i] == '5')
 | 
						|
	  {
 | 
						|
	    for(i++ ; i < ndigits; i++)
 | 
						|
	      {
 | 
						|
		if (digits[i] != '0')
 | 
						|
		  goto do_rnd;
 | 
						|
	      }
 | 
						|
	    /* It is a tie so round to even.  */
 | 
						|
	    switch (digits[nafter + nbefore - 1])
 | 
						|
	      {
 | 
						|
		case '1':
 | 
						|
		case '3':
 | 
						|
		case '5':
 | 
						|
		case '7':
 | 
						|
		case '9':
 | 
						|
		  /* If odd, round away from zero to even.  */
 | 
						|
		  break;
 | 
						|
		default:
 | 
						|
		  /* If even, skip rounding, truncate to even.  */
 | 
						|
		  goto skip;
 | 
						|
	      }
 | 
						|
	  }
 | 
						|
	/* Fall through.  */
 | 
						|
	/* The ROUND_COMPATIBLE is rounding away from zero when there is a tie.  */
 | 
						|
      case ROUND_COMPATIBLE:
 | 
						|
	rchar = '5';
 | 
						|
	goto do_rnd;
 | 
						|
    }
 | 
						|
 | 
						|
  updown:
 | 
						|
 | 
						|
  rchar = '0';
 | 
						|
  if (ft != FMT_F && w > 0 && d == 0 && p == 0)
 | 
						|
    nbefore = 1;
 | 
						|
  /* Scan for trailing zeros to see if we really need to round it.  */
 | 
						|
  for(i = nbefore + nafter; i < ndigits; i++)
 | 
						|
    {
 | 
						|
      if (digits[i] != '0')
 | 
						|
	goto do_rnd;
 | 
						|
    }
 | 
						|
  goto skip;
 | 
						|
    
 | 
						|
  do_rnd:
 | 
						|
 
 | 
						|
  if (nbefore + nafter == 0)
 | 
						|
    /* Handle the case Fw.0 and value < 1.0 */
 | 
						|
    {
 | 
						|
      ndigits = 0;
 | 
						|
      if (digits[0] >= rchar)
 | 
						|
	{
 | 
						|
	  /* We rounded to zero but shouldn't have */
 | 
						|
	  nbefore = 1;
 | 
						|
	  digits--;
 | 
						|
	  digits[0] = '1';
 | 
						|
	  ndigits = 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else if (nbefore + nafter < ndigits)
 | 
						|
    {
 | 
						|
      i = ndigits = nbefore + nafter;
 | 
						|
      if (digits[i] >= rchar)
 | 
						|
	{
 | 
						|
	  /* Propagate the carry.  */
 | 
						|
	  for (i--; i >= 0; i--)
 | 
						|
	    {
 | 
						|
	      if (digits[i] != '9')
 | 
						|
		{
 | 
						|
		  digits[i]++;
 | 
						|
		  break;
 | 
						|
		}
 | 
						|
	      digits[i] = '0';
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (i < 0)
 | 
						|
	    {
 | 
						|
	      /* The carry overflowed.  Fortunately we have some spare
 | 
						|
	         space at the start of the buffer.  We may discard some
 | 
						|
	         digits, but this is ok because we already know they are
 | 
						|
	         zero.  */
 | 
						|
	      digits--;
 | 
						|
	      digits[0] = '1';
 | 
						|
	      if (ft == FMT_F)
 | 
						|
		{
 | 
						|
		  if (nzero > 0)
 | 
						|
		    {
 | 
						|
		      nzero--;
 | 
						|
		      nafter++;
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    nbefore++;
 | 
						|
		}
 | 
						|
	      else if (ft == FMT_EN)
 | 
						|
		{
 | 
						|
		  nbefore++;
 | 
						|
		  if (nbefore == 4)
 | 
						|
		    {
 | 
						|
		      nbefore = 1;
 | 
						|
		      e += 3;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		e++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  skip:
 | 
						|
 | 
						|
  /* Calculate the format of the exponent field.  */
 | 
						|
  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
 | 
						|
    {
 | 
						|
      edigits = 1;
 | 
						|
      for (i = abs (e); i >= 10; i /= 10)
 | 
						|
	edigits++;
 | 
						|
 | 
						|
      if (f->u.real.e < 0)
 | 
						|
	{
 | 
						|
	  /* Width not specified.  Must be no more than 3 digits.  */
 | 
						|
	  if (e > 999 || e < -999)
 | 
						|
	    edigits = -1;
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      edigits = 4;
 | 
						|
	      if (e > 99 || e < -99)
 | 
						|
		expchar = ' ';
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  /* Exponent width specified, check it is wide enough.  */
 | 
						|
	  if (edigits > f->u.real.e)
 | 
						|
	    edigits = -1;
 | 
						|
	  else
 | 
						|
	    edigits = f->u.real.e + 2;
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else
 | 
						|
    edigits = 0;
 | 
						|
 | 
						|
  /* 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.  */
 | 
						|
  int hasdot = 0;
 | 
						|
  for (i = 0; i < ndigits + hasdot; i++)
 | 
						|
    {
 | 
						|
      if (digits[i] == '.')
 | 
						|
	hasdot = 1;
 | 
						|
      else 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 + hasdot)
 | 
						|
    {
 | 
						|
      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)
 | 
						|
        sign = calculate_sign (dtp, sign_bit);
 | 
						|
      else
 | 
						|
	sign = calculate_sign (dtp, 0);
 | 
						|
    }
 | 
						|
 | 
						|
  /* Pick a field size if none was specified, taking into account small
 | 
						|
     values that may have been rounded to zero.  */
 | 
						|
  if (w <= 0)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
  if (sign != S_NONE)
 | 
						|
    nblanks--;
 | 
						|
 | 
						|
  if (dtp->u.p.g0_no_blanks)
 | 
						|
    {
 | 
						|
      w -= nblanks;
 | 
						|
      nblanks = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Create the ouput buffer.  */
 | 
						|
  out = write_block (dtp, w);
 | 
						|
  if (out == NULL)
 | 
						|
    return false;
 | 
						|
 | 
						|
  /* Check the value fits in the specified field width.  */
 | 
						|
  if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
 | 
						|
    {
 | 
						|
      if (unlikely (is_char4_unit (dtp)))
 | 
						|
	{
 | 
						|
	  gfc_char4_t *out4 = (gfc_char4_t *) out;
 | 
						|
	  memset4 (out4, '*', w);
 | 
						|
	  return false;
 | 
						|
	}
 | 
						|
      star_fill (out, w);
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
  /* See if we have space for a zero before the decimal point.  */
 | 
						|
  if (nbefore == 0 && nblanks > 0)
 | 
						|
    {
 | 
						|
      leadzero = 1;
 | 
						|
      nblanks--;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    leadzero = 0;
 | 
						|
 | 
						|
  /* For internal character(kind=4) units, we duplicate the code used for
 | 
						|
     regular output slightly modified.  This needs to be maintained
 | 
						|
     consistent with the regular code that follows this block.  */
 | 
						|
  if (unlikely (is_char4_unit (dtp)))
 | 
						|
    {
 | 
						|
      gfc_char4_t *out4 = (gfc_char4_t *) out;
 | 
						|
      /* Pad to full field width.  */
 | 
						|
 | 
						|
      if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
 | 
						|
	{
 | 
						|
	  memset4 (out4, ' ', nblanks);
 | 
						|
	  out4 += nblanks;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Output the initial sign (if any).  */
 | 
						|
      if (sign == S_PLUS)
 | 
						|
	*(out4++) = '+';
 | 
						|
      else if (sign == S_MINUS)
 | 
						|
	*(out4++) = '-';
 | 
						|
 | 
						|
      /* Output an optional leading zero.  */
 | 
						|
      if (leadzero)
 | 
						|
	*(out4++) = '0';
 | 
						|
 | 
						|
      /* Output the part before the decimal point, padding with zeros.  */
 | 
						|
      if (nbefore > 0)
 | 
						|
	{
 | 
						|
	  if (nbefore > ndigits)
 | 
						|
	    {
 | 
						|
	      i = ndigits;
 | 
						|
	      memcpy4 (out4, digits, i);
 | 
						|
	      ndigits = 0;
 | 
						|
	      while (i < nbefore)
 | 
						|
		out4[i++] = '0';
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      i = nbefore;
 | 
						|
	      memcpy4 (out4, digits, i);
 | 
						|
	      ndigits -= i;
 | 
						|
	    }
 | 
						|
 | 
						|
	  digits += i;
 | 
						|
	  out4 += nbefore;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Output the decimal point.  */
 | 
						|
      *(out4++) = dtp->u.p.current_unit->decimal_status
 | 
						|
		    == DECIMAL_POINT ? '.' : ',';
 | 
						|
      if (ft == FMT_F 
 | 
						|
	  && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED 
 | 
						|
	      || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
 | 
						|
	digits++;
 | 
						|
 | 
						|
      /* Output leading zeros after the decimal point.  */
 | 
						|
      if (nzero > 0)
 | 
						|
	{
 | 
						|
	  for (i = 0; i < nzero; i++)
 | 
						|
	    *(out4++) = '0';
 | 
						|
	}
 | 
						|
 | 
						|
      /* Output digits after the decimal point, padding with zeros.  */
 | 
						|
      if (nafter > 0)
 | 
						|
	{
 | 
						|
	  if (nafter > ndigits)
 | 
						|
	    i = ndigits;
 | 
						|
	  else
 | 
						|
	    i = nafter;
 | 
						|
 | 
						|
	  memcpy4 (out4, digits, i);
 | 
						|
	  while (i < nafter)
 | 
						|
	    out4[i++] = '0';
 | 
						|
 | 
						|
	  digits += i;
 | 
						|
	  ndigits -= i;
 | 
						|
	  out4 += nafter;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Output the exponent.  */
 | 
						|
      if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
 | 
						|
	{
 | 
						|
	  if (expchar != ' ')
 | 
						|
	    {
 | 
						|
	      *(out4++) = expchar;
 | 
						|
	      edigits--;
 | 
						|
	    }
 | 
						|
	  snprintf (buffer, size, "%+0*d", edigits, e);
 | 
						|
	  memcpy4 (out4, buffer, edigits);
 | 
						|
	}
 | 
						|
 | 
						|
      if (dtp->u.p.no_leading_blank)
 | 
						|
	{
 | 
						|
	  out4 += edigits;
 | 
						|
	  memset4 (out4, ' ' , nblanks);
 | 
						|
	  dtp->u.p.no_leading_blank = 0;
 | 
						|
	}
 | 
						|
      return true;
 | 
						|
    } /* End of character(kind=4) internal unit code.  */
 | 
						|
 | 
						|
  /* Pad to full field width.  */
 | 
						|
 | 
						|
  if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
 | 
						|
    {
 | 
						|
      memset (out, ' ', nblanks);
 | 
						|
      out += nblanks;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output the initial sign (if any).  */
 | 
						|
  if (sign == S_PLUS)
 | 
						|
    *(out++) = '+';
 | 
						|
  else if (sign == S_MINUS)
 | 
						|
    *(out++) = '-';
 | 
						|
 | 
						|
  /* Output an optional leading zero.  */
 | 
						|
  if (leadzero)
 | 
						|
    *(out++) = '0';
 | 
						|
 | 
						|
  /* Output the part before the decimal point, padding with zeros.  */
 | 
						|
  if (nbefore > 0)
 | 
						|
    {
 | 
						|
      if (nbefore > ndigits)
 | 
						|
	{
 | 
						|
	  i = ndigits;
 | 
						|
	  memcpy (out, digits, i);
 | 
						|
	  ndigits = 0;
 | 
						|
	  while (i < nbefore)
 | 
						|
	    out[i++] = '0';
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  i = nbefore;
 | 
						|
	  memcpy (out, digits, i);
 | 
						|
	  ndigits -= i;
 | 
						|
	}
 | 
						|
 | 
						|
      digits += i;
 | 
						|
      out += nbefore;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output the decimal point.  */
 | 
						|
  *(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
 | 
						|
  if (ft == FMT_F
 | 
						|
	  && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED 
 | 
						|
	      || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
 | 
						|
    digits++;
 | 
						|
 | 
						|
  /* Output leading zeros after the decimal point.  */
 | 
						|
  if (nzero > 0)
 | 
						|
    {
 | 
						|
      for (i = 0; i < nzero; i++)
 | 
						|
	*(out++) = '0';
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output digits after the decimal point, padding with zeros.  */
 | 
						|
  if (nafter > 0)
 | 
						|
    {
 | 
						|
      if (nafter > ndigits)
 | 
						|
	i = ndigits;
 | 
						|
      else
 | 
						|
	i = nafter;
 | 
						|
 | 
						|
      memcpy (out, digits, i);
 | 
						|
      while (i < nafter)
 | 
						|
	out[i++] = '0';
 | 
						|
 | 
						|
      digits += i;
 | 
						|
      ndigits -= i;
 | 
						|
      out += nafter;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Output the exponent.  */
 | 
						|
  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
 | 
						|
    {
 | 
						|
      if (expchar != ' ')
 | 
						|
	{
 | 
						|
	  *(out++) = expchar;
 | 
						|
	  edigits--;
 | 
						|
	}
 | 
						|
      snprintf (buffer, size, "%+0*d", edigits, e);
 | 
						|
      memcpy (out, buffer, edigits);
 | 
						|
    }
 | 
						|
 | 
						|
  if (dtp->u.p.no_leading_blank)
 | 
						|
    {
 | 
						|
      out += edigits;
 | 
						|
      memset( out , ' ' , nblanks );
 | 
						|
      dtp->u.p.no_leading_blank = 0;
 | 
						|
    }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Write "Infinite" or "Nan" as appropriate for the given format.  */
 | 
						|
 | 
						|
static void
 | 
						|
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) || dtp->u.p.g0_no_blanks)
 | 
						|
	{
 | 
						|
	  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)))
 | 
						|
	    {
 | 
						|
	      gfc_char4_t *p4 = (gfc_char4_t *) p;
 | 
						|
	      memset4 (p4, '*', nb);
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    memset (p, '*', nb);
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
 | 
						|
      if (unlikely (is_char4_unit (dtp)))
 | 
						|
	{
 | 
						|
	  gfc_char4_t *p4 = (gfc_char4_t *) p;
 | 
						|
	  memset4 (p4, ' ', nb);
 | 
						|
	}
 | 
						|
      else
 | 
						|
	memset(p, ' ', nb);
 | 
						|
 | 
						|
      if (!isnan_flag)
 | 
						|
	{
 | 
						|
	  if (sign_bit)
 | 
						|
	    {
 | 
						|
	      /* If the sign is negative and the width is 3, there is
 | 
						|
		 insufficient room to output '-Inf', so output asterisks */
 | 
						|
	      if (nb == 3)
 | 
						|
		{
 | 
						|
		  if (unlikely (is_char4_unit (dtp)))
 | 
						|
		    {
 | 
						|
		      gfc_char4_t *p4 = (gfc_char4_t *) p;
 | 
						|
		      memset4 (p4, '*', nb);
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    memset (p, '*', nb);
 | 
						|
		  return;
 | 
						|
		}
 | 
						|
	      /* The negative sign is mandatory */
 | 
						|
	      fin = '-';
 | 
						|
	    }    
 | 
						|
	  else
 | 
						|
	    /* The positive sign is optional, but we output it for
 | 
						|
	       consistency */
 | 
						|
	    fin = '+';
 | 
						|
	    
 | 
						|
	  if (unlikely (is_char4_unit (dtp)))
 | 
						|
	    {
 | 
						|
	      gfc_char4_t *p4 = (gfc_char4_t *) p;
 | 
						|
 | 
						|
	      if (nb > mark)
 | 
						|
		/* We have room, so output 'Infinity' */
 | 
						|
		memcpy4 (p4 + nb - 8, "Infinity", 8);
 | 
						|
	      else
 | 
						|
		/* 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);
 | 
						|
 | 
						|
	      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 > mark)
 | 
						|
	    /* We have room, so output 'Infinity' */
 | 
						|
	    memcpy(p + nb - 8, "Infinity", 8);
 | 
						|
	  else
 | 
						|
	    /* For the case of width equals 8, there is not enough room
 | 
						|
	       for the sign and 'Infinity' so we go with 'Inf' */
 | 
						|
	    memcpy(p + nb - 3, "Inf", 3);
 | 
						|
 | 
						|
	  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)))
 | 
						|
	    {
 | 
						|
	      gfc_char4_t *p4 = (gfc_char4_t *) p;
 | 
						|
	      memcpy4 (p4 + nb - 3, "NaN", 3);
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    memcpy(p + nb - 3, "NaN", 3);
 | 
						|
	}
 | 
						|
      return;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Returns the value of 10**d.  */
 | 
						|
 | 
						|
#define CALCULATE_EXP(x) \
 | 
						|
static GFC_REAL_ ## x \
 | 
						|
calculate_exp_ ## x  (int d)\
 | 
						|
{\
 | 
						|
  int i;\
 | 
						|
  GFC_REAL_ ## x r = 1.0;\
 | 
						|
  for (i = 0; i< (d >= 0 ? d : -d); i++)\
 | 
						|
    r *= 10;\
 | 
						|
  r = (d >= 0) ? r : 1.0 / r;\
 | 
						|
  return r;\
 | 
						|
}
 | 
						|
 | 
						|
CALCULATE_EXP(4)
 | 
						|
 | 
						|
CALCULATE_EXP(8)
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_10
 | 
						|
CALCULATE_EXP(10)
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_16
 | 
						|
CALCULATE_EXP(16)
 | 
						|
#endif
 | 
						|
#undef CALCULATE_EXP
 | 
						|
 | 
						|
 | 
						|
/* Define a macro to build code for write_float.  */
 | 
						|
 | 
						|
  /* Note: Before output_float is called, snprintf is used to print to buffer the
 | 
						|
     number in the format +D.DDDDe+ddd. 
 | 
						|
 | 
						|
     #   The result will always contain a decimal point, even if no
 | 
						|
	 digits follow it
 | 
						|
 | 
						|
     -   The converted value is to be left adjusted on the field boundary
 | 
						|
 | 
						|
     +   A sign (+ or -) always be placed before a number
 | 
						|
 | 
						|
     *   prec is used as the precision
 | 
						|
 | 
						|
     e format: [-]d.ddde±dd where there is one digit before the
 | 
						|
       decimal-point character and the number of digits after it is
 | 
						|
       equal to the precision. The exponent always contains at least two
 | 
						|
       digits; if the value is zero, the exponent is 00.  */
 | 
						|
 | 
						|
 | 
						|
#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
 | 
						|
#define TOKENPASTE2(x, y) x ## y
 | 
						|
 | 
						|
#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
 | 
						|
 | 
						|
#define DTOA2(prec,val)					\
 | 
						|
snprintf (buffer, size, "%+-#.*e", (prec), (val))
 | 
						|
 | 
						|
#define DTOA2L(prec,val)				\
 | 
						|
snprintf (buffer, size, "%+-#.*Le", (prec), (val))
 | 
						|
 | 
						|
 | 
						|
#if defined(GFC_REAL_16_IS_FLOAT128)
 | 
						|
#define DTOA2Q(prec,val)							\
 | 
						|
quadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
 | 
						|
#endif
 | 
						|
 | 
						|
#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
 | 
						|
 | 
						|
/* For F format, we print to the buffer with f format.  */
 | 
						|
#define FDTOA2(prec,val)							\
 | 
						|
snprintf (buffer, size, "%+-#.*f", (prec), (val))
 | 
						|
 | 
						|
#define FDTOA2L(prec,val)						\
 | 
						|
snprintf (buffer, size, "%+-#.*Lf", (prec), (val))
 | 
						|
 | 
						|
 | 
						|
#if defined(GFC_REAL_16_IS_FLOAT128)
 | 
						|
#define FDTOA2Q(prec,val)			       \
 | 
						|
quadmath_snprintf (buffer, size, "%+-#.*Qf", \
 | 
						|
			     (prec), (val))
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if defined(GFC_REAL_16_IS_FLOAT128)
 | 
						|
#define ISFINITE2Q(val) finiteq(val)
 | 
						|
#endif
 | 
						|
#define ISFINITE2(val) isfinite(val)
 | 
						|
#define ISFINITE2L(val) isfinite(val)
 | 
						|
 | 
						|
#define ISFINITE(suff,val) TOKENPASTE(ISFINITE2,suff)(val)
 | 
						|
 | 
						|
 | 
						|
#if defined(GFC_REAL_16_IS_FLOAT128)
 | 
						|
#define SIGNBIT2Q(val) signbitq(val)
 | 
						|
#endif
 | 
						|
#define SIGNBIT2(val) signbit(val)
 | 
						|
#define SIGNBIT2L(val) signbit(val)
 | 
						|
 | 
						|
#define SIGNBIT(suff,val) TOKENPASTE(SIGNBIT2,suff)(val)
 | 
						|
 | 
						|
 | 
						|
#if defined(GFC_REAL_16_IS_FLOAT128)
 | 
						|
#define ISNAN2Q(val) isnanq(val)
 | 
						|
#endif
 | 
						|
#define ISNAN2(val) isnan(val)
 | 
						|
#define ISNAN2L(val) isnan(val)
 | 
						|
 | 
						|
#define ISNAN(suff,val) TOKENPASTE(ISNAN2,suff)(val)
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Generate corresponding I/O format for FMT_G and output.
 | 
						|
   The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
 | 
						|
   LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
 | 
						|
 | 
						|
   Data Magnitude                              Equivalent Conversion
 | 
						|
   0< m < 0.1-0.5*10**(-d-1)                   Ew.d[Ee]
 | 
						|
   m = 0                                       F(w-n).(d-1), n' '
 | 
						|
   0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d)     F(w-n).d, n' '
 | 
						|
   1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1)      F(w-n).(d-1), n' '
 | 
						|
   10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2)  F(w-n).(d-2), n' '
 | 
						|
   ................                           ..........
 | 
						|
   10**(d-1)-0.5*10**(-1)<= m <10**d-0.5       F(w-n).0,n(' ')
 | 
						|
   m >= 10**d-0.5                              Ew.d[Ee]
 | 
						|
 | 
						|
   notes: for Gw.d ,  n' ' means 4 blanks
 | 
						|
	  for Gw.dEe, n' ' means e+2 blanks
 | 
						|
	  for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
 | 
						|
	  the asm volatile is required for 32-bit x86 platforms.  */
 | 
						|
 | 
						|
#define OUTPUT_FLOAT_FMT_G(x,y)			\
 | 
						|
static void \
 | 
						|
output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
 | 
						|
		      GFC_REAL_ ## x m, char *buffer, size_t size, \
 | 
						|
			  int sign_bit, bool zero_flag, int comp_d) \
 | 
						|
{ \
 | 
						|
  int e = f->u.real.e;\
 | 
						|
  int d = f->u.real.d;\
 | 
						|
  int w = f->u.real.w;\
 | 
						|
  fnode newf;\
 | 
						|
  GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
 | 
						|
  int low, high, mid;\
 | 
						|
  int ubound, lbound;\
 | 
						|
  char *p, pad = ' ';\
 | 
						|
  int save_scale_factor, nb = 0;\
 | 
						|
  bool result;\
 | 
						|
  int nprinted, precision;\
 | 
						|
  volatile GFC_REAL_ ## x temp;\
 | 
						|
\
 | 
						|
  save_scale_factor = dtp->u.p.scale_factor;\
 | 
						|
\
 | 
						|
  switch (dtp->u.p.current_unit->round_status)\
 | 
						|
    {\
 | 
						|
      case ROUND_ZERO:\
 | 
						|
	r = sign_bit ? 1.0 : 0.0;\
 | 
						|
	break;\
 | 
						|
      case ROUND_UP:\
 | 
						|
	r = 1.0;\
 | 
						|
	break;\
 | 
						|
      case ROUND_DOWN:\
 | 
						|
	r = 0.0;\
 | 
						|
	break;\
 | 
						|
      default:\
 | 
						|
	break;\
 | 
						|
    }\
 | 
						|
\
 | 
						|
  exp_d = calculate_exp_ ## x (d);\
 | 
						|
  r_sc = (1 - r / exp_d);\
 | 
						|
  temp = 0.1 * r_sc;\
 | 
						|
  if ((m > 0.0 && ((m < temp) || (r >= (exp_d - m))))\
 | 
						|
      || ((m == 0.0) && !(compile_options.allow_std\
 | 
						|
			  & (GFC_STD_F2003 | GFC_STD_F2008)))\
 | 
						|
      ||  d == 0)\
 | 
						|
    { \
 | 
						|
      newf.format = FMT_E;\
 | 
						|
      newf.u.real.w = w;\
 | 
						|
      newf.u.real.d = d - comp_d;\
 | 
						|
      newf.u.real.e = e;\
 | 
						|
      nb = 0;\
 | 
						|
      precision = determine_precision (dtp, &newf, x);\
 | 
						|
      nprinted = DTOA(y,precision,m);			     \
 | 
						|
      goto finish;\
 | 
						|
    }\
 | 
						|
\
 | 
						|
  mid = 0;\
 | 
						|
  low = 0;\
 | 
						|
  high = d + 1;\
 | 
						|
  lbound = 0;\
 | 
						|
  ubound = d + 1;\
 | 
						|
\
 | 
						|
  while (low <= high)\
 | 
						|
    { \
 | 
						|
      mid = (low + high) / 2;\
 | 
						|
\
 | 
						|
      temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
 | 
						|
\
 | 
						|
      if (m < temp)\
 | 
						|
        { \
 | 
						|
          ubound = mid;\
 | 
						|
          if (ubound == lbound + 1)\
 | 
						|
            break;\
 | 
						|
          high = mid - 1;\
 | 
						|
        }\
 | 
						|
      else if (m > temp)\
 | 
						|
        { \
 | 
						|
          lbound = mid;\
 | 
						|
          if (ubound == lbound + 1)\
 | 
						|
            { \
 | 
						|
              mid ++;\
 | 
						|
              break;\
 | 
						|
            }\
 | 
						|
          low = mid + 1;\
 | 
						|
        }\
 | 
						|
      else\
 | 
						|
	{\
 | 
						|
	  mid++;\
 | 
						|
	  break;\
 | 
						|
	}\
 | 
						|
    }\
 | 
						|
\
 | 
						|
  nb = e <= 0 ? 4 : e + 2;\
 | 
						|
  nb = nb >= w ? w - 1 : nb;\
 | 
						|
  newf.format = FMT_F;\
 | 
						|
  newf.u.real.w = w - nb;\
 | 
						|
  newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
 | 
						|
  dtp->u.p.scale_factor = 0;\
 | 
						|
  precision = determine_precision (dtp, &newf, x);	\
 | 
						|
  nprinted = FDTOA(y,precision,m);					\
 | 
						|
\
 | 
						|
 finish:\
 | 
						|
    result = output_float (dtp, &newf, buffer, size, nprinted, precision,\
 | 
						|
			   sign_bit, zero_flag);\
 | 
						|
  dtp->u.p.scale_factor = save_scale_factor;\
 | 
						|
\
 | 
						|
\
 | 
						|
  if (nb > 0 && !dtp->u.p.g0_no_blanks)\
 | 
						|
    {\
 | 
						|
      p = write_block (dtp, nb);\
 | 
						|
      if (p == NULL)\
 | 
						|
	return;\
 | 
						|
      if (!result)\
 | 
						|
        pad = '*';\
 | 
						|
      if (unlikely (is_char4_unit (dtp)))\
 | 
						|
	{\
 | 
						|
	  gfc_char4_t *p4 = (gfc_char4_t *) p;\
 | 
						|
	  memset4 (p4, pad, nb);\
 | 
						|
	}\
 | 
						|
      else \
 | 
						|
	memset (p, pad, nb);\
 | 
						|
    }\
 | 
						|
}\
 | 
						|
 | 
						|
OUTPUT_FLOAT_FMT_G(4,)
 | 
						|
 | 
						|
OUTPUT_FLOAT_FMT_G(8,)
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_10
 | 
						|
OUTPUT_FLOAT_FMT_G(10,L)
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_16
 | 
						|
# ifdef GFC_REAL_16_IS_FLOAT128
 | 
						|
OUTPUT_FLOAT_FMT_G(16,Q)
 | 
						|
#else
 | 
						|
OUTPUT_FLOAT_FMT_G(16,L)
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#undef OUTPUT_FLOAT_FMT_G
 | 
						|
 | 
						|
 | 
						|
/* EN format is tricky since the number of significant digits depends
 | 
						|
   on the magnitude.  Solve it by first printing a temporary value and
 | 
						|
   figure out the number of significant digits from the printed
 | 
						|
   exponent.  Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
 | 
						|
   10.0**e even when the final result will not be rounded to 10.0**e.
 | 
						|
   For these values the exponent returned by atoi has to be decremented
 | 
						|
   by one. The values y in the ranges
 | 
						|
       (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))  
 | 
						|
        (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
 | 
						|
         (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
 | 
						|
   are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
 | 
						|
   100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
 | 
						|
   represents d zeroes, by the lines 279 to 297. */
 | 
						|
 | 
						|
#define EN_PREC(x,y)\
 | 
						|
{\
 | 
						|
    volatile GFC_REAL_ ## x tmp, one = 1.0;\
 | 
						|
    tmp = * (GFC_REAL_ ## x *)source;\
 | 
						|
    if (ISFINITE (y,tmp))\
 | 
						|
      {\
 | 
						|
	nprinted = DTOA(y,0,tmp);\
 | 
						|
	int e = atoi (&buffer[4]);\
 | 
						|
	if (buffer[1] == '1')\
 | 
						|
	  {\
 | 
						|
	    tmp = (calculate_exp_ ## x (-e)) * tmp;\
 | 
						|
	    tmp = one - (tmp < 0 ? -tmp : tmp);	\
 | 
						|
	    if (tmp > 0)\
 | 
						|
	      e = e - 1;\
 | 
						|
	  }\
 | 
						|
	nbefore = e%3;\
 | 
						|
	if (nbefore < 0)\
 | 
						|
	  nbefore = 3 + nbefore;\
 | 
						|
      }\
 | 
						|
    else\
 | 
						|
      nprinted = -1;\
 | 
						|
}\
 | 
						|
 | 
						|
static int
 | 
						|
determine_en_precision (st_parameter_dt *dtp, const fnode *f, 
 | 
						|
			const char *source, int len)
 | 
						|
{
 | 
						|
  int nprinted;
 | 
						|
  char buffer[10];
 | 
						|
  const size_t size = 10;
 | 
						|
  int nbefore; /* digits before decimal point - 1.  */
 | 
						|
 | 
						|
  switch (len)
 | 
						|
    {
 | 
						|
    case 4:
 | 
						|
      EN_PREC(4,)
 | 
						|
      break;
 | 
						|
 | 
						|
    case 8:
 | 
						|
      EN_PREC(8,)
 | 
						|
      break;
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_10
 | 
						|
    case 10:
 | 
						|
      EN_PREC(10,L)
 | 
						|
      break;
 | 
						|
#endif
 | 
						|
#ifdef HAVE_GFC_REAL_16
 | 
						|
    case 16:
 | 
						|
# ifdef GFC_REAL_16_IS_FLOAT128
 | 
						|
      EN_PREC(16,Q)
 | 
						|
# else
 | 
						|
      EN_PREC(16,L)
 | 
						|
# endif
 | 
						|
      break;
 | 
						|
#endif
 | 
						|
    default:
 | 
						|
      internal_error (NULL, "bad real kind");
 | 
						|
    }
 | 
						|
 | 
						|
  if (nprinted == -1)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  int prec = f->u.real.d + nbefore;
 | 
						|
  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
 | 
						|
      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
 | 
						|
    prec += 2 * len + 4;
 | 
						|
  return prec;
 | 
						|
}
 | 
						|
  
 | 
						|
 | 
						|
#define WRITE_FLOAT(x,y)\
 | 
						|
{\
 | 
						|
	GFC_REAL_ ## x tmp;\
 | 
						|
	tmp = * (GFC_REAL_ ## x *)source;\
 | 
						|
	sign_bit = SIGNBIT (y,tmp);\
 | 
						|
	if (!ISFINITE (y,tmp))\
 | 
						|
	  { \
 | 
						|
	    write_infnan (dtp, f, ISNAN (y,tmp), sign_bit);\
 | 
						|
	    return;\
 | 
						|
	  }\
 | 
						|
	tmp = sign_bit ? -tmp : tmp;\
 | 
						|
	zero_flag = (tmp == 0.0);\
 | 
						|
	if (f->format == FMT_G)\
 | 
						|
	  output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
 | 
						|
				    zero_flag, comp_d);\
 | 
						|
	else\
 | 
						|
	  {\
 | 
						|
	    if (f->format == FMT_F)\
 | 
						|
	      nprinted = FDTOA(y,precision,tmp);		\
 | 
						|
	    else\
 | 
						|
	      nprinted = DTOA(y,precision,tmp);					\
 | 
						|
	    output_float (dtp, f, buffer, size, nprinted, precision,\
 | 
						|
			  sign_bit, zero_flag);\
 | 
						|
	  }\
 | 
						|
}\
 | 
						|
 | 
						|
/* Output a real number according to its format.  */
 | 
						|
 | 
						|
static void
 | 
						|
write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \
 | 
						|
            int len, int comp_d)
 | 
						|
{
 | 
						|
  int sign_bit, nprinted;
 | 
						|
  int precision;  /* Precision for snprintf call.  */
 | 
						|
  bool zero_flag;
 | 
						|
 | 
						|
  if (f->format != FMT_EN)
 | 
						|
    precision = determine_precision (dtp, f, len);
 | 
						|
  else
 | 
						|
    precision = determine_en_precision (dtp, f, source, len);
 | 
						|
 | 
						|
  /* 4932 is the maximum exponent of long double and quad precision, 3
 | 
						|
     extra characters for the sign, the decimal point, and the
 | 
						|
     trailing null, and finally some extra digits depending on the
 | 
						|
     requested precision.  */
 | 
						|
  const size_t size = 4932 + 3 + precision;
 | 
						|
#define BUF_STACK_SZ 5000
 | 
						|
  char buf_stack[BUF_STACK_SZ];
 | 
						|
  char *buffer;
 | 
						|
  if (size > BUF_STACK_SZ)
 | 
						|
     buffer = xmalloc (size);
 | 
						|
  else
 | 
						|
     buffer = buf_stack;
 | 
						|
 | 
						|
  switch (len)
 | 
						|
    {
 | 
						|
    case 4:
 | 
						|
      WRITE_FLOAT(4,)
 | 
						|
      break;
 | 
						|
 | 
						|
    case 8:
 | 
						|
      WRITE_FLOAT(8,)
 | 
						|
      break;
 | 
						|
 | 
						|
#ifdef HAVE_GFC_REAL_10
 | 
						|
    case 10:
 | 
						|
      WRITE_FLOAT(10,L)
 | 
						|
      break;
 | 
						|
#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:
 | 
						|
      internal_error (NULL, "bad real kind");
 | 
						|
    }
 | 
						|
  if (size > BUF_STACK_SZ)
 | 
						|
     free (buffer);
 | 
						|
}
 |