| /* Copyright (C) 2007-2020 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; | 
 | } | 
 |  | 
 |  | 
 | /* Build a real number according to its format which is FMT_G free.  */ | 
 |  | 
 | static void | 
 | build_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer, | 
 | 		    size_t size, int nprinted, int precision, int sign_bit, | 
 | 		    bool zero_flag, int npad, int default_width, char *result, | 
 | 		    size_t *len) | 
 | { | 
 |   char *put; | 
 |   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; | 
 |   if (f->u.real.w == DEFAULT_WIDTH) | 
 |     /* This codepath can only be reached with -fdec-format-defaults. */ | 
 |     { | 
 |       w = default_width; | 
 |       d = precision; | 
 |     } | 
 |   else | 
 |     { | 
 |       w = f->u.real.w; | 
 |       d = f->u.real.d; | 
 |     } | 
 |   p = dtp->u.p.scale_factor; | 
 |   *len = 0; | 
 |  | 
 |   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; | 
 |       if ((w > 0) && (nbefore > (int) size)) | 
 |         { | 
 | 	  *len = w; | 
 | 	  star_fill (result, w); | 
 | 	  result[w] = '\0'; | 
 | 	  return; | 
 | 	} | 
 |       /* 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; | 
 | 	} | 
 |       if (p <= -d || p >= d + 2) | 
 | 	{ | 
 | 	  generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor " | 
 | 			  "out of range in format specifier 'E' or 'D'"); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       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'; | 
 |   /* Do not reset nbefore for FMT_F and FMT_EN.  */ | 
 |   if (ft != FMT_F && ft !=FMT_EN && 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 if (f->u.real.e == 0) | 
 | 	{ | 
 | 	  /* Zero width specified, no leading zeros in exponent  */ | 
 | 	  if (e > 999 || e < -999) | 
 | 	    edigits = 6; | 
 | 	  else if (e > 99 || e < -99) | 
 | 	    edigits = 5; | 
 | 	  else if (e > 9 || e < -9) | 
 | 	    edigits = 4; | 
 | 	  else | 
 | 	    edigits = 3; | 
 | 	} | 
 |       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--; | 
 |  | 
 |   /* See if we have space for a zero before the decimal point.  */ | 
 |   if (nbefore == 0 && nblanks > 0) | 
 |     { | 
 |       leadzero = 1; | 
 |       nblanks--; | 
 |     } | 
 |   else | 
 |     leadzero = 0; | 
 |  | 
 |   if (dtp->u.p.g0_no_blanks) | 
 |     { | 
 |       w -= nblanks; | 
 |       nblanks = 0; | 
 |     } | 
 |  | 
 |   /* Create the final float string.  */ | 
 |   *len = w + npad; | 
 |   put = result; | 
 |  | 
 |   /* Check the value fits in the specified field width.  */ | 
 |   if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE)) | 
 |     { | 
 |       star_fill (put, *len); | 
 |       return; | 
 |     } | 
 |  | 
 |   /* Pad to full field width.  */ | 
 |   if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank) | 
 |     { | 
 |       memset (put, ' ', nblanks); | 
 |       put += nblanks; | 
 |     } | 
 |  | 
 |   /* Set the initial sign (if any).  */ | 
 |   if (sign == S_PLUS) | 
 |     *(put++) = '+'; | 
 |   else if (sign == S_MINUS) | 
 |     *(put++) = '-'; | 
 |  | 
 |   /* Set an optional leading zero.  */ | 
 |   if (leadzero) | 
 |     *(put++) = '0'; | 
 |  | 
 |   /* Set the part before the decimal point, padding with zeros.  */ | 
 |   if (nbefore > 0) | 
 |     { | 
 |       if (nbefore > ndigits) | 
 | 	{ | 
 | 	  i = ndigits; | 
 | 	  memcpy (put, digits, i); | 
 | 	  ndigits = 0; | 
 | 	  while (i < nbefore) | 
 | 	    put[i++] = '0'; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  i = nbefore; | 
 | 	  memcpy (put, digits, i); | 
 | 	  ndigits -= i; | 
 | 	} | 
 |  | 
 |       digits += i; | 
 |       put += nbefore; | 
 |     } | 
 |  | 
 |   /* Set the decimal point.  */ | 
 |   *(put++) = 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++; | 
 |  | 
 |   /* Set leading zeros after the decimal point.  */ | 
 |   if (nzero > 0) | 
 |     { | 
 |       for (i = 0; i < nzero; i++) | 
 | 	*(put++) = '0'; | 
 |     } | 
 |  | 
 |   /* Set digits after the decimal point, padding with zeros.  */ | 
 |   if (ndigits >= 0 && nafter > 0) | 
 |     { | 
 |       if (nafter > ndigits) | 
 | 	i = ndigits; | 
 |       else | 
 | 	i = nafter; | 
 |  | 
 |       if (i > 0) | 
 | 	memcpy (put, digits, i); | 
 |       while (i < nafter) | 
 | 	put[i++] = '0'; | 
 |  | 
 |       digits += i; | 
 |       ndigits -= i; | 
 |       put += nafter; | 
 |     } | 
 |  | 
 |   /* Set the exponent.  */ | 
 |   if (expchar && !(dtp->u.p.g0_no_blanks && e == 0)) | 
 |     { | 
 |       if (expchar != ' ') | 
 | 	{ | 
 | 	  *(put++) = expchar; | 
 | 	  edigits--; | 
 | 	} | 
 |       snprintf (buffer, size, "%+0*d", edigits, e); | 
 |       memcpy (put, buffer, edigits); | 
 |       put += edigits; | 
 |     } | 
 |  | 
 |   if (dtp->u.p.no_leading_blank) | 
 |     { | 
 |       memset (put , ' ' , nblanks); | 
 |       dtp->u.p.no_leading_blank = 0; | 
 |       put += nblanks; | 
 |     } | 
 |  | 
 |   if (npad > 0 && !dtp->u.p.g0_no_blanks) | 
 |     { | 
 |       memset (put , ' ' , npad); | 
 |       put += npad; | 
 |     } | 
 |  | 
 |   /* NULL terminate the string.  */ | 
 |   *put = '\0'; | 
 |    | 
 |   return; | 
 | } | 
 |  | 
 |  | 
 | /* Write "Infinite" or "Nan" as appropriate for the given format.  */ | 
 |  | 
 | static void | 
 | build_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag, | 
 | 		    int sign_bit, char *p, size_t *len) | 
 | { | 
 |   char 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; | 
 |       *len = nb; | 
 |  | 
 |       /* 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; | 
 | 	  *len = nb; | 
 | 	} | 
 |  | 
 |       p[*len] = '\0'; | 
 |       if (nb < 3) | 
 | 	{ | 
 | 	  memset (p, '*', nb); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       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) | 
 | 		{ | 
 | 		  memset (p, '*', nb); | 
 | 		  return; | 
 | 		} | 
 | 	      /* The negative sign is mandatory */ | 
 | 	      fin = '-'; | 
 | 	    }     | 
 | 	  else | 
 | 	    /* The positive sign is optional, but we output it for | 
 | 	       consistency */ | 
 | 	    fin = '+'; | 
 | 	     | 
 | 	  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 | 
 | 	memcpy(p + nb - 3, "NaN", 3); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /* 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 macros to build code for format_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 | 
 |  | 
 |  | 
 | /* 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 (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; | 
 | } | 
 |    | 
 |  | 
 | /* Generate corresponding I/O format. 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 FORMAT_FLOAT(x,y)\ | 
 | {\ | 
 |   int npad = 0;\ | 
 |   GFC_REAL_ ## x m;\ | 
 |   m = * (GFC_REAL_ ## x *)source;\ | 
 |   sign_bit = signbit (m);\ | 
 |   if (!isfinite (m))\ | 
 |     { \ | 
 |       build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\ | 
 |       return;\ | 
 |     }\ | 
 |   m = sign_bit ? -m : m;\ | 
 |   zero_flag = (m == 0.0);\ | 
 |   if (f->format == FMT_G)\ | 
 |     {\ | 
 |       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;\ | 
 |       int save_scale_factor;\ | 
 |       volatile GFC_REAL_ ## x temp;\ | 
 |       save_scale_factor = dtp->u.p.scale_factor;\ | 
 |       if (w == DEFAULT_WIDTH)\ | 
 | 	{\ | 
 | 	  w = default_width;\ | 
 | 	  d = precision;\ | 
 | 	}\ | 
 |       /* The switch between FMT_E and FMT_F is based on the absolute value.  \ | 
 |          Set r=0 for rounding toward zero and r = 1 otherwise.  \ | 
 | 	 If (exp_d - m) == 1 there is no rounding needed.  */\ | 
 |       switch (dtp->u.p.current_unit->round_status)\ | 
 | 	{\ | 
 | 	  case ROUND_ZERO:\ | 
 | 	    r = 0.0;\ | 
 | 	    break;\ | 
 | 	  case ROUND_UP:\ | 
 | 	    r = sign_bit ? 0.0 : 1.0;\ | 
 | 	    break;\ | 
 | 	  case ROUND_DOWN:\ | 
 | 	    r = sign_bit ? 1.0 : 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 < 1 && r >= (exp_d - m))\ | 
 | 				  || (r == 1 && 1 > (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;\ | 
 | 	  npad = 0;\ | 
 | 	  precision = determine_precision (dtp, &newf, x);\ | 
 | 	  nprinted = DTOA(y,precision,m);\ | 
 | 	}\ | 
 |       else \ | 
 | 	{\ | 
 | 	  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;\ | 
 | 		}\ | 
 | 	    }\ | 
 | 	  npad = e <= 0 ? 4 : e + 2;\ | 
 | 	  npad = npad >= w ? w - 1 : npad;\ | 
 | 	  npad = dtp->u.p.g0_no_blanks ? 0 : npad;\ | 
 | 	  newf.format = FMT_F;\ | 
 | 	  newf.u.real.w = w - npad;\ | 
 | 	  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);\ | 
 | 	}\ | 
 |       build_float_string (dtp, &newf, buffer, size, nprinted, precision,\ | 
 | 				   sign_bit, zero_flag, npad, default_width,\ | 
 | 				   result, res_len);\ | 
 |       dtp->u.p.scale_factor = save_scale_factor;\ | 
 |     }\ | 
 |   else\ | 
 |     {\ | 
 |       if (f->format == FMT_F)\ | 
 | 	nprinted = FDTOA(y,precision,m);\ | 
 |       else\ | 
 | 	nprinted = DTOA(y,precision,m);\ | 
 |       build_float_string (dtp, f, buffer, size, nprinted, precision,\ | 
 | 				   sign_bit, zero_flag, npad, default_width,\ | 
 | 				   result, res_len);\ | 
 |     }\ | 
 | }\ | 
 |  | 
 | /* Output a real number according to its format.  */ | 
 |  | 
 |  | 
 | static void | 
 | get_float_string (st_parameter_dt *dtp, const fnode *f, const char *source, | 
 | 		  int kind, int comp_d, char *buffer, int precision, | 
 | 		  size_t size, char *result, size_t *res_len) | 
 | { | 
 |   int sign_bit, nprinted; | 
 |   bool zero_flag; | 
 |   int default_width = 0; | 
 |  | 
 |   if (f->u.real.w == DEFAULT_WIDTH) | 
 |     /* This codepath can only be reached with -fdec-format-defaults. The default | 
 |      * values are based on those used in the Oracle Fortran compiler. | 
 |      */ | 
 |     { | 
 |       default_width = default_width_for_float (kind); | 
 |       precision = default_precision_for_float (kind); | 
 |     } | 
 |  | 
 |   switch (kind) | 
 |     { | 
 |     case 4: | 
 |       FORMAT_FLOAT(4,) | 
 |       break; | 
 |  | 
 |     case 8: | 
 |       FORMAT_FLOAT(8,) | 
 |       break; | 
 |  | 
 | #ifdef HAVE_GFC_REAL_10 | 
 |     case 10: | 
 |       FORMAT_FLOAT(10,L) | 
 |       break; | 
 | #endif | 
 | #ifdef HAVE_GFC_REAL_16 | 
 |     case 16: | 
 | # ifdef GFC_REAL_16_IS_FLOAT128 | 
 |       FORMAT_FLOAT(16,Q) | 
 | # else | 
 |       FORMAT_FLOAT(16,L) | 
 | # endif | 
 |       break; | 
 | #endif | 
 |     default: | 
 |       internal_error (NULL, "bad real kind"); | 
 |     } | 
 |   return; | 
 | } |