xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/io/write_float.def (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg/* Copyright (C) 2007-2020 Free Software Foundation, Inc.
2627f7eb2Smrg   Contributed by Andy Vaught
3627f7eb2Smrg   Write float code factoring to this file by Jerry DeLisle
4627f7eb2Smrg   F2003 I/O support contributed by Jerry DeLisle
5627f7eb2Smrg
6627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran).
7627f7eb2Smrg
8627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or modify
9627f7eb2Smrgit under the terms of the GNU General Public License as published by
10627f7eb2Smrgthe Free Software Foundation; either version 3, or (at your option)
11627f7eb2Smrgany later version.
12627f7eb2Smrg
13627f7eb2SmrgLibgfortran is distributed in the hope that it will be useful,
14627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of
15627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16627f7eb2SmrgGNU General Public License for more details.
17627f7eb2Smrg
18627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional
19627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version
20627f7eb2Smrg3.1, as published by the Free Software Foundation.
21627f7eb2Smrg
22627f7eb2SmrgYou should have received a copy of the GNU General Public License and
23627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program;
24627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25627f7eb2Smrg<http://www.gnu.org/licenses/>.  */
26627f7eb2Smrg
27627f7eb2Smrg#include "config.h"
28627f7eb2Smrg
29627f7eb2Smrgtypedef enum
30627f7eb2Smrg{ S_NONE, S_MINUS, S_PLUS }
31627f7eb2Smrgsign_t;
32627f7eb2Smrg
33627f7eb2Smrg/* Given a flag that indicates if a value is negative or not, return a
34627f7eb2Smrg   sign_t that gives the sign that we need to produce.  */
35627f7eb2Smrg
36627f7eb2Smrgstatic sign_t
37627f7eb2Smrgcalculate_sign (st_parameter_dt *dtp, int negative_flag)
38627f7eb2Smrg{
39627f7eb2Smrg  sign_t s = S_NONE;
40627f7eb2Smrg
41627f7eb2Smrg  if (negative_flag)
42627f7eb2Smrg    s = S_MINUS;
43627f7eb2Smrg  else
44627f7eb2Smrg    switch (dtp->u.p.sign_status)
45627f7eb2Smrg      {
46627f7eb2Smrg      case SIGN_SP:	/* Show sign. */
47627f7eb2Smrg	s = S_PLUS;
48627f7eb2Smrg	break;
49627f7eb2Smrg      case SIGN_SS:	/* Suppress sign. */
50627f7eb2Smrg	s = S_NONE;
51627f7eb2Smrg	break;
52627f7eb2Smrg      case SIGN_S:	/* Processor defined. */
53627f7eb2Smrg      case SIGN_UNSPECIFIED:
54627f7eb2Smrg	s = options.optional_plus ? S_PLUS : S_NONE;
55627f7eb2Smrg	break;
56627f7eb2Smrg      }
57627f7eb2Smrg
58627f7eb2Smrg  return s;
59627f7eb2Smrg}
60627f7eb2Smrg
61627f7eb2Smrg
62627f7eb2Smrg/* Determine the precision except for EN format. For G format,
63627f7eb2Smrg   determines an upper bound to be used for sizing the buffer. */
64627f7eb2Smrg
65627f7eb2Smrgstatic int
66627f7eb2Smrgdetermine_precision (st_parameter_dt * dtp, const fnode * f, int len)
67627f7eb2Smrg{
68627f7eb2Smrg  int precision = f->u.real.d;
69627f7eb2Smrg
70627f7eb2Smrg  switch (f->format)
71627f7eb2Smrg    {
72627f7eb2Smrg    case FMT_F:
73627f7eb2Smrg    case FMT_G:
74627f7eb2Smrg      precision += dtp->u.p.scale_factor;
75627f7eb2Smrg      break;
76627f7eb2Smrg    case FMT_ES:
77627f7eb2Smrg      /* Scale factor has no effect on output.  */
78627f7eb2Smrg      break;
79627f7eb2Smrg    case FMT_E:
80627f7eb2Smrg    case FMT_D:
81627f7eb2Smrg      /* See F2008 10.7.2.3.3.6 */
82627f7eb2Smrg      if (dtp->u.p.scale_factor <= 0)
83627f7eb2Smrg	precision += dtp->u.p.scale_factor - 1;
84627f7eb2Smrg      break;
85627f7eb2Smrg    default:
86627f7eb2Smrg      return -1;
87627f7eb2Smrg    }
88627f7eb2Smrg
89627f7eb2Smrg  /* If the scale factor has a large negative value, we must do our
90627f7eb2Smrg     own rounding? Use ROUND='NEAREST', which should be what snprintf
91627f7eb2Smrg     is using as well.  */
92627f7eb2Smrg  if (precision < 0 &&
93627f7eb2Smrg      (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
94627f7eb2Smrg       || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
95627f7eb2Smrg    dtp->u.p.current_unit->round_status = ROUND_NEAREST;
96627f7eb2Smrg
97627f7eb2Smrg  /* Add extra guard digits up to at least full precision when we do
98627f7eb2Smrg     our own rounding.  */
99627f7eb2Smrg  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
100627f7eb2Smrg      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
101627f7eb2Smrg    {
102627f7eb2Smrg      precision += 2 * len + 4;
103627f7eb2Smrg      if (precision < 0)
104627f7eb2Smrg	precision = 0;
105627f7eb2Smrg    }
106627f7eb2Smrg
107627f7eb2Smrg  return precision;
108627f7eb2Smrg}
109627f7eb2Smrg
110627f7eb2Smrg
111627f7eb2Smrg/* Build a real number according to its format which is FMT_G free.  */
112627f7eb2Smrg
113627f7eb2Smrgstatic void
114627f7eb2Smrgbuild_float_string (st_parameter_dt *dtp, const fnode *f, char *buffer,
115627f7eb2Smrg		    size_t size, int nprinted, int precision, int sign_bit,
116*4c3eb207Smrg		    bool zero_flag, int npad, int default_width, char *result,
117*4c3eb207Smrg		    size_t *len)
118627f7eb2Smrg{
119627f7eb2Smrg  char *put;
120627f7eb2Smrg  char *digits;
121627f7eb2Smrg  int e, w, d, p, i;
122627f7eb2Smrg  char expchar, rchar;
123627f7eb2Smrg  format_token ft;
124627f7eb2Smrg  /* Number of digits before the decimal point.  */
125627f7eb2Smrg  int nbefore;
126627f7eb2Smrg  /* Number of zeros after the decimal point.  */
127627f7eb2Smrg  int nzero;
128627f7eb2Smrg  /* Number of digits after the decimal point.  */
129627f7eb2Smrg  int nafter;
130627f7eb2Smrg  int leadzero;
131627f7eb2Smrg  int nblanks;
132627f7eb2Smrg  int ndigits, edigits;
133627f7eb2Smrg  sign_t sign;
134627f7eb2Smrg
135627f7eb2Smrg  ft = f->format;
136*4c3eb207Smrg  if (f->u.real.w == DEFAULT_WIDTH)
137*4c3eb207Smrg    /* This codepath can only be reached with -fdec-format-defaults. */
138*4c3eb207Smrg    {
139*4c3eb207Smrg      w = default_width;
140*4c3eb207Smrg      d = precision;
141*4c3eb207Smrg    }
142*4c3eb207Smrg  else
143*4c3eb207Smrg    {
144627f7eb2Smrg      w = f->u.real.w;
145627f7eb2Smrg      d = f->u.real.d;
146*4c3eb207Smrg    }
147627f7eb2Smrg  p = dtp->u.p.scale_factor;
148627f7eb2Smrg  *len = 0;
149627f7eb2Smrg
150627f7eb2Smrg  rchar = '5';
151627f7eb2Smrg
152627f7eb2Smrg  /* We should always know the field width and precision.  */
153627f7eb2Smrg  if (d < 0)
154627f7eb2Smrg    internal_error (&dtp->common, "Unspecified precision");
155627f7eb2Smrg
156627f7eb2Smrg  sign = calculate_sign (dtp, sign_bit);
157627f7eb2Smrg
158627f7eb2Smrg  /* Calculate total number of digits.  */
159627f7eb2Smrg  if (ft == FMT_F)
160627f7eb2Smrg    ndigits = nprinted - 2;
161627f7eb2Smrg  else
162627f7eb2Smrg    ndigits = precision + 1;
163627f7eb2Smrg
164627f7eb2Smrg  /* Read the exponent back in.  */
165627f7eb2Smrg  if (ft != FMT_F)
166627f7eb2Smrg    e = atoi (&buffer[ndigits + 3]) + 1;
167627f7eb2Smrg  else
168627f7eb2Smrg    e = 0;
169627f7eb2Smrg
170627f7eb2Smrg  /* Make sure zero comes out as 0.0e0.   */
171627f7eb2Smrg  if (zero_flag)
172627f7eb2Smrg    e = 0;
173627f7eb2Smrg
174627f7eb2Smrg  /* Normalize the fractional component.  */
175627f7eb2Smrg  if (ft != FMT_F)
176627f7eb2Smrg    {
177627f7eb2Smrg      buffer[2] = buffer[1];
178627f7eb2Smrg      digits = &buffer[2];
179627f7eb2Smrg    }
180627f7eb2Smrg  else
181627f7eb2Smrg    digits = &buffer[1];
182627f7eb2Smrg
183627f7eb2Smrg  /* Figure out where to place the decimal point.  */
184627f7eb2Smrg  switch (ft)
185627f7eb2Smrg    {
186627f7eb2Smrg    case FMT_F:
187627f7eb2Smrg      nbefore = ndigits - precision;
188627f7eb2Smrg      if ((w > 0) && (nbefore > (int) size))
189627f7eb2Smrg        {
190627f7eb2Smrg	  *len = w;
191627f7eb2Smrg	  star_fill (result, w);
192627f7eb2Smrg	  result[w] = '\0';
193627f7eb2Smrg	  return;
194627f7eb2Smrg	}
195627f7eb2Smrg      /* Make sure the decimal point is a '.'; depending on the
196627f7eb2Smrg	 locale, this might not be the case otherwise.  */
197627f7eb2Smrg      digits[nbefore] = '.';
198627f7eb2Smrg      if (p != 0)
199627f7eb2Smrg	{
200627f7eb2Smrg	  if (p > 0)
201627f7eb2Smrg	    {
202627f7eb2Smrg	      memmove (digits + nbefore, digits + nbefore + 1, p);
203627f7eb2Smrg	      digits[nbefore + p] = '.';
204627f7eb2Smrg	      nbefore += p;
205627f7eb2Smrg	      nafter = d;
206627f7eb2Smrg	      nzero = 0;
207627f7eb2Smrg	    }
208627f7eb2Smrg	  else /* p < 0  */
209627f7eb2Smrg	    {
210627f7eb2Smrg	      if (nbefore + p >= 0)
211627f7eb2Smrg		{
212627f7eb2Smrg		  nzero = 0;
213627f7eb2Smrg		  memmove (digits + nbefore + p + 1, digits + nbefore + p, -p);
214627f7eb2Smrg		  nbefore += p;
215627f7eb2Smrg		  digits[nbefore] = '.';
216627f7eb2Smrg		  nafter = d;
217627f7eb2Smrg		}
218627f7eb2Smrg	      else
219627f7eb2Smrg		{
220627f7eb2Smrg		  nzero = -(nbefore + p);
221627f7eb2Smrg		  memmove (digits + 1, digits, nbefore);
222627f7eb2Smrg		  nafter = d - nzero;
223627f7eb2Smrg		  if (nafter == 0 && d > 0)
224627f7eb2Smrg		    {
225627f7eb2Smrg		      /* This is needed to get the correct rounding. */
226627f7eb2Smrg		      memmove (digits + 1, digits, ndigits - 1);
227627f7eb2Smrg		      digits[1] = '0';
228627f7eb2Smrg		      nafter = 1;
229627f7eb2Smrg		      nzero = d - 1;
230627f7eb2Smrg		    }
231627f7eb2Smrg		  else if (nafter < 0)
232627f7eb2Smrg		    {
233627f7eb2Smrg		      /* Reset digits to 0 in order to get correct rounding
234627f7eb2Smrg			 towards infinity. */
235627f7eb2Smrg		      for (i = 0; i < ndigits; i++)
236627f7eb2Smrg			digits[i] = '0';
237627f7eb2Smrg		      digits[ndigits - 1] = '1';
238627f7eb2Smrg		      nafter = d;
239627f7eb2Smrg		      nzero = 0;
240627f7eb2Smrg		    }
241627f7eb2Smrg		  nbefore = 0;
242627f7eb2Smrg		}
243627f7eb2Smrg	    }
244627f7eb2Smrg	}
245627f7eb2Smrg      else
246627f7eb2Smrg	{
247627f7eb2Smrg	  nzero = 0;
248627f7eb2Smrg	  nafter = d;
249627f7eb2Smrg	}
250627f7eb2Smrg
251627f7eb2Smrg      while (digits[0] == '0' && nbefore > 0)
252627f7eb2Smrg	{
253627f7eb2Smrg	  digits++;
254627f7eb2Smrg	  nbefore--;
255627f7eb2Smrg	  ndigits--;
256627f7eb2Smrg	}
257627f7eb2Smrg
258627f7eb2Smrg      expchar = 0;
259627f7eb2Smrg      /* If we need to do rounding ourselves, get rid of the dot by
260627f7eb2Smrg	 moving the fractional part.  */
261627f7eb2Smrg      if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
262627f7eb2Smrg	  && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
263627f7eb2Smrg	memmove (digits + nbefore, digits + nbefore + 1, ndigits - nbefore);
264627f7eb2Smrg      break;
265627f7eb2Smrg
266627f7eb2Smrg    case FMT_E:
267627f7eb2Smrg    case FMT_D:
268627f7eb2Smrg      i = dtp->u.p.scale_factor;
269*4c3eb207Smrg      if (d < 0 && p == 0)
270627f7eb2Smrg	{
271627f7eb2Smrg	  generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
272627f7eb2Smrg			  "greater than zero in format specifier 'E' or 'D'");
273627f7eb2Smrg	  return;
274627f7eb2Smrg	}
275627f7eb2Smrg      if (p <= -d || p >= d + 2)
276627f7eb2Smrg	{
277627f7eb2Smrg	  generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
278627f7eb2Smrg			  "out of range in format specifier 'E' or 'D'");
279627f7eb2Smrg	  return;
280627f7eb2Smrg	}
281627f7eb2Smrg
282627f7eb2Smrg      if (!zero_flag)
283627f7eb2Smrg	e -= p;
284627f7eb2Smrg      if (p < 0)
285627f7eb2Smrg	{
286627f7eb2Smrg	  nbefore = 0;
287627f7eb2Smrg	  nzero = -p;
288627f7eb2Smrg	  nafter = d + p;
289627f7eb2Smrg	}
290627f7eb2Smrg      else if (p > 0)
291627f7eb2Smrg	{
292627f7eb2Smrg	  nbefore = p;
293627f7eb2Smrg	  nzero = 0;
294627f7eb2Smrg	  nafter = (d - p) + 1;
295627f7eb2Smrg	}
296627f7eb2Smrg      else /* p == 0 */
297627f7eb2Smrg	{
298627f7eb2Smrg	  nbefore = 0;
299627f7eb2Smrg	  nzero = 0;
300627f7eb2Smrg	  nafter = d;
301627f7eb2Smrg	}
302627f7eb2Smrg
303627f7eb2Smrg      if (ft == FMT_E)
304627f7eb2Smrg	expchar = 'E';
305627f7eb2Smrg      else
306627f7eb2Smrg	expchar = 'D';
307627f7eb2Smrg      break;
308627f7eb2Smrg
309627f7eb2Smrg    case FMT_EN:
310627f7eb2Smrg      /* The exponent must be a multiple of three, with 1-3 digits before
311627f7eb2Smrg	 the decimal point.  */
312627f7eb2Smrg      if (!zero_flag)
313627f7eb2Smrg        e--;
314627f7eb2Smrg      if (e >= 0)
315627f7eb2Smrg	nbefore = e % 3;
316627f7eb2Smrg      else
317627f7eb2Smrg	{
318627f7eb2Smrg	  nbefore = (-e) % 3;
319627f7eb2Smrg	  if (nbefore != 0)
320627f7eb2Smrg	    nbefore = 3 - nbefore;
321627f7eb2Smrg	}
322627f7eb2Smrg      e -= nbefore;
323627f7eb2Smrg      nbefore++;
324627f7eb2Smrg      nzero = 0;
325627f7eb2Smrg      nafter = d;
326627f7eb2Smrg      expchar = 'E';
327627f7eb2Smrg      break;
328627f7eb2Smrg
329627f7eb2Smrg    case FMT_ES:
330627f7eb2Smrg      if (!zero_flag)
331627f7eb2Smrg        e--;
332627f7eb2Smrg      nbefore = 1;
333627f7eb2Smrg      nzero = 0;
334627f7eb2Smrg      nafter = d;
335627f7eb2Smrg      expchar = 'E';
336627f7eb2Smrg      break;
337627f7eb2Smrg
338627f7eb2Smrg    default:
339627f7eb2Smrg      /* Should never happen.  */
340627f7eb2Smrg      internal_error (&dtp->common, "Unexpected format token");
341627f7eb2Smrg    }
342627f7eb2Smrg
343627f7eb2Smrg  if (zero_flag)
344627f7eb2Smrg    goto skip;
345627f7eb2Smrg
346627f7eb2Smrg  /* Round the value.  The value being rounded is an unsigned magnitude.  */
347627f7eb2Smrg  switch (dtp->u.p.current_unit->round_status)
348627f7eb2Smrg    {
349627f7eb2Smrg      /* For processor defined and unspecified rounding we use
350627f7eb2Smrg	 snprintf to print the exact number of digits needed, and thus
351627f7eb2Smrg	 let snprintf handle the rounding.  On system claiming support
352627f7eb2Smrg	 for IEEE 754, this ought to be round to nearest, ties to
353627f7eb2Smrg	 even, corresponding to the Fortran ROUND='NEAREST'.  */
354627f7eb2Smrg      case ROUND_PROCDEFINED:
355627f7eb2Smrg      case ROUND_UNSPECIFIED:
356627f7eb2Smrg      case ROUND_ZERO: /* Do nothing and truncation occurs.  */
357627f7eb2Smrg	goto skip;
358627f7eb2Smrg      case ROUND_UP:
359627f7eb2Smrg	if (sign_bit)
360627f7eb2Smrg	  goto skip;
361627f7eb2Smrg	goto updown;
362627f7eb2Smrg      case ROUND_DOWN:
363627f7eb2Smrg	if (!sign_bit)
364627f7eb2Smrg	  goto skip;
365627f7eb2Smrg	goto updown;
366627f7eb2Smrg      case ROUND_NEAREST:
367627f7eb2Smrg	/* Round compatible unless there is a tie. A tie is a 5 with
368627f7eb2Smrg	   all trailing zero's.  */
369627f7eb2Smrg	i = nafter + nbefore;
370627f7eb2Smrg	if (digits[i] == '5')
371627f7eb2Smrg	  {
372627f7eb2Smrg	    for(i++ ; i < ndigits; i++)
373627f7eb2Smrg	      {
374627f7eb2Smrg		if (digits[i] != '0')
375627f7eb2Smrg		  goto do_rnd;
376627f7eb2Smrg	      }
377627f7eb2Smrg	    /* It is a tie so round to even.  */
378627f7eb2Smrg	    switch (digits[nafter + nbefore - 1])
379627f7eb2Smrg	      {
380627f7eb2Smrg		case '1':
381627f7eb2Smrg		case '3':
382627f7eb2Smrg		case '5':
383627f7eb2Smrg		case '7':
384627f7eb2Smrg		case '9':
385627f7eb2Smrg		  /* If odd, round away from zero to even.  */
386627f7eb2Smrg		  break;
387627f7eb2Smrg		default:
388627f7eb2Smrg		  /* If even, skip rounding, truncate to even.  */
389627f7eb2Smrg		  goto skip;
390627f7eb2Smrg	      }
391627f7eb2Smrg	  }
392627f7eb2Smrg	/* Fall through.  */
393627f7eb2Smrg	/* The ROUND_COMPATIBLE is rounding away from zero when there is a tie.  */
394627f7eb2Smrg      case ROUND_COMPATIBLE:
395627f7eb2Smrg	rchar = '5';
396627f7eb2Smrg	goto do_rnd;
397627f7eb2Smrg    }
398627f7eb2Smrg
399627f7eb2Smrg  updown:
400627f7eb2Smrg
401627f7eb2Smrg  rchar = '0';
402*4c3eb207Smrg  /* Do not reset nbefore for FMT_F and FMT_EN.  */
403*4c3eb207Smrg  if (ft != FMT_F && ft !=FMT_EN && w > 0 && d == 0 && p == 0)
404627f7eb2Smrg    nbefore = 1;
405627f7eb2Smrg  /* Scan for trailing zeros to see if we really need to round it.  */
406627f7eb2Smrg  for(i = nbefore + nafter; i < ndigits; i++)
407627f7eb2Smrg    {
408627f7eb2Smrg      if (digits[i] != '0')
409627f7eb2Smrg	goto do_rnd;
410627f7eb2Smrg    }
411627f7eb2Smrg  goto skip;
412627f7eb2Smrg
413627f7eb2Smrg  do_rnd:
414627f7eb2Smrg
415627f7eb2Smrg  if (nbefore + nafter == 0)
416627f7eb2Smrg    /* Handle the case Fw.0 and value < 1.0 */
417627f7eb2Smrg    {
418627f7eb2Smrg      ndigits = 0;
419627f7eb2Smrg      if (digits[0] >= rchar)
420627f7eb2Smrg	{
421627f7eb2Smrg	  /* We rounded to zero but shouldn't have */
422627f7eb2Smrg	  nbefore = 1;
423627f7eb2Smrg	  digits--;
424627f7eb2Smrg	  digits[0] = '1';
425627f7eb2Smrg	  ndigits = 1;
426627f7eb2Smrg	}
427627f7eb2Smrg    }
428627f7eb2Smrg  else if (nbefore + nafter < ndigits)
429627f7eb2Smrg    {
430627f7eb2Smrg      i = ndigits = nbefore + nafter;
431627f7eb2Smrg      if (digits[i] >= rchar)
432627f7eb2Smrg	{
433627f7eb2Smrg	  /* Propagate the carry.  */
434627f7eb2Smrg	  for (i--; i >= 0; i--)
435627f7eb2Smrg	    {
436627f7eb2Smrg	      if (digits[i] != '9')
437627f7eb2Smrg		{
438627f7eb2Smrg		  digits[i]++;
439627f7eb2Smrg		  break;
440627f7eb2Smrg		}
441627f7eb2Smrg	      digits[i] = '0';
442627f7eb2Smrg	    }
443627f7eb2Smrg
444627f7eb2Smrg	  if (i < 0)
445627f7eb2Smrg	    {
446627f7eb2Smrg	      /* The carry overflowed.  Fortunately we have some spare
447627f7eb2Smrg	         space at the start of the buffer.  We may discard some
448627f7eb2Smrg	         digits, but this is ok because we already know they are
449627f7eb2Smrg	         zero.  */
450627f7eb2Smrg	      digits--;
451627f7eb2Smrg	      digits[0] = '1';
452627f7eb2Smrg	      if (ft == FMT_F)
453627f7eb2Smrg		{
454627f7eb2Smrg		  if (nzero > 0)
455627f7eb2Smrg		    {
456627f7eb2Smrg		      nzero--;
457627f7eb2Smrg		      nafter++;
458627f7eb2Smrg		    }
459627f7eb2Smrg		  else
460627f7eb2Smrg		    nbefore++;
461627f7eb2Smrg		}
462627f7eb2Smrg	      else if (ft == FMT_EN)
463627f7eb2Smrg		{
464627f7eb2Smrg		  nbefore++;
465627f7eb2Smrg		  if (nbefore == 4)
466627f7eb2Smrg		    {
467627f7eb2Smrg		      nbefore = 1;
468627f7eb2Smrg		      e += 3;
469627f7eb2Smrg		    }
470627f7eb2Smrg		}
471627f7eb2Smrg	      else
472627f7eb2Smrg		e++;
473627f7eb2Smrg	    }
474627f7eb2Smrg	}
475627f7eb2Smrg    }
476627f7eb2Smrg
477627f7eb2Smrg  skip:
478627f7eb2Smrg
479627f7eb2Smrg  /* Calculate the format of the exponent field.  */
480627f7eb2Smrg  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
481627f7eb2Smrg    {
482627f7eb2Smrg      edigits = 1;
483627f7eb2Smrg      for (i = abs (e); i >= 10; i /= 10)
484627f7eb2Smrg	edigits++;
485627f7eb2Smrg
486627f7eb2Smrg      if (f->u.real.e < 0)
487627f7eb2Smrg	{
488627f7eb2Smrg	  /* Width not specified.  Must be no more than 3 digits.  */
489627f7eb2Smrg	  if (e > 999 || e < -999)
490627f7eb2Smrg	    edigits = -1;
491627f7eb2Smrg	  else
492627f7eb2Smrg	    {
493627f7eb2Smrg	      edigits = 4;
494627f7eb2Smrg	      if (e > 99 || e < -99)
495627f7eb2Smrg		expchar = ' ';
496627f7eb2Smrg	    }
497627f7eb2Smrg	}
498*4c3eb207Smrg      else if (f->u.real.e == 0)
499*4c3eb207Smrg	{
500*4c3eb207Smrg	  /* Zero width specified, no leading zeros in exponent  */
501*4c3eb207Smrg	  if (e > 999 || e < -999)
502*4c3eb207Smrg	    edigits = 6;
503*4c3eb207Smrg	  else if (e > 99 || e < -99)
504*4c3eb207Smrg	    edigits = 5;
505*4c3eb207Smrg	  else if (e > 9 || e < -9)
506*4c3eb207Smrg	    edigits = 4;
507*4c3eb207Smrg	  else
508*4c3eb207Smrg	    edigits = 3;
509*4c3eb207Smrg	}
510627f7eb2Smrg      else
511627f7eb2Smrg	{
512627f7eb2Smrg	  /* Exponent width specified, check it is wide enough.  */
513627f7eb2Smrg	  if (edigits > f->u.real.e)
514627f7eb2Smrg	    edigits = -1;
515627f7eb2Smrg	  else
516627f7eb2Smrg	    edigits = f->u.real.e + 2;
517627f7eb2Smrg	}
518627f7eb2Smrg    }
519627f7eb2Smrg  else
520627f7eb2Smrg    edigits = 0;
521627f7eb2Smrg
522627f7eb2Smrg  /* Scan the digits string and count the number of zeros.  If we make it
523627f7eb2Smrg     all the way through the loop, we know the value is zero after the
524627f7eb2Smrg     rounding completed above.  */
525627f7eb2Smrg  int hasdot = 0;
526627f7eb2Smrg  for (i = 0; i < ndigits + hasdot; i++)
527627f7eb2Smrg    {
528627f7eb2Smrg      if (digits[i] == '.')
529627f7eb2Smrg	hasdot = 1;
530627f7eb2Smrg      else if (digits[i] != '0')
531627f7eb2Smrg	break;
532627f7eb2Smrg    }
533627f7eb2Smrg
534627f7eb2Smrg  /* To format properly, we need to know if the rounded result is zero and if
535627f7eb2Smrg     so, we set the zero_flag which may have been already set for
536627f7eb2Smrg     actual zero.  */
537627f7eb2Smrg  if (i == ndigits + hasdot)
538627f7eb2Smrg    {
539627f7eb2Smrg      zero_flag = true;
540627f7eb2Smrg      /* The output is zero, so set the sign according to the sign bit unless
541627f7eb2Smrg	 -fno-sign-zero was specified.  */
542627f7eb2Smrg      if (compile_options.sign_zero == 1)
543627f7eb2Smrg        sign = calculate_sign (dtp, sign_bit);
544627f7eb2Smrg      else
545627f7eb2Smrg	sign = calculate_sign (dtp, 0);
546627f7eb2Smrg    }
547627f7eb2Smrg
548627f7eb2Smrg  /* Pick a field size if none was specified, taking into account small
549627f7eb2Smrg     values that may have been rounded to zero.  */
550627f7eb2Smrg  if (w <= 0)
551627f7eb2Smrg    {
552627f7eb2Smrg      if (zero_flag)
553627f7eb2Smrg	w = d + (sign != S_NONE ? 2 : 1) + (d == 0 ? 1 : 0);
554627f7eb2Smrg      else
555627f7eb2Smrg	{
556627f7eb2Smrg	  w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
557627f7eb2Smrg	  w = w == 1 ? 2 : w;
558627f7eb2Smrg	}
559627f7eb2Smrg    }
560627f7eb2Smrg
561627f7eb2Smrg  /* Work out how much padding is needed.  */
562627f7eb2Smrg  nblanks = w - (nbefore + nzero + nafter + edigits + 1);
563627f7eb2Smrg  if (sign != S_NONE)
564627f7eb2Smrg    nblanks--;
565627f7eb2Smrg
566627f7eb2Smrg  /* See if we have space for a zero before the decimal point.  */
567627f7eb2Smrg  if (nbefore == 0 && nblanks > 0)
568627f7eb2Smrg    {
569627f7eb2Smrg      leadzero = 1;
570627f7eb2Smrg      nblanks--;
571627f7eb2Smrg    }
572627f7eb2Smrg  else
573627f7eb2Smrg    leadzero = 0;
574627f7eb2Smrg
575627f7eb2Smrg  if (dtp->u.p.g0_no_blanks)
576627f7eb2Smrg    {
577627f7eb2Smrg      w -= nblanks;
578627f7eb2Smrg      nblanks = 0;
579627f7eb2Smrg    }
580627f7eb2Smrg
581627f7eb2Smrg  /* Create the final float string.  */
582627f7eb2Smrg  *len = w + npad;
583627f7eb2Smrg  put = result;
584627f7eb2Smrg
585627f7eb2Smrg  /* Check the value fits in the specified field width.  */
586627f7eb2Smrg  if (nblanks < 0 || edigits == -1 || w == 1 || (w == 2 && sign != S_NONE))
587627f7eb2Smrg    {
588627f7eb2Smrg      star_fill (put, *len);
589627f7eb2Smrg      return;
590627f7eb2Smrg    }
591627f7eb2Smrg
592627f7eb2Smrg  /* Pad to full field width.  */
593627f7eb2Smrg  if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
594627f7eb2Smrg    {
595627f7eb2Smrg      memset (put, ' ', nblanks);
596627f7eb2Smrg      put += nblanks;
597627f7eb2Smrg    }
598627f7eb2Smrg
599627f7eb2Smrg  /* Set the initial sign (if any).  */
600627f7eb2Smrg  if (sign == S_PLUS)
601627f7eb2Smrg    *(put++) = '+';
602627f7eb2Smrg  else if (sign == S_MINUS)
603627f7eb2Smrg    *(put++) = '-';
604627f7eb2Smrg
605627f7eb2Smrg  /* Set an optional leading zero.  */
606627f7eb2Smrg  if (leadzero)
607627f7eb2Smrg    *(put++) = '0';
608627f7eb2Smrg
609627f7eb2Smrg  /* Set the part before the decimal point, padding with zeros.  */
610627f7eb2Smrg  if (nbefore > 0)
611627f7eb2Smrg    {
612627f7eb2Smrg      if (nbefore > ndigits)
613627f7eb2Smrg	{
614627f7eb2Smrg	  i = ndigits;
615627f7eb2Smrg	  memcpy (put, digits, i);
616627f7eb2Smrg	  ndigits = 0;
617627f7eb2Smrg	  while (i < nbefore)
618627f7eb2Smrg	    put[i++] = '0';
619627f7eb2Smrg	}
620627f7eb2Smrg      else
621627f7eb2Smrg	{
622627f7eb2Smrg	  i = nbefore;
623627f7eb2Smrg	  memcpy (put, digits, i);
624627f7eb2Smrg	  ndigits -= i;
625627f7eb2Smrg	}
626627f7eb2Smrg
627627f7eb2Smrg      digits += i;
628627f7eb2Smrg      put += nbefore;
629627f7eb2Smrg    }
630627f7eb2Smrg
631627f7eb2Smrg  /* Set the decimal point.  */
632627f7eb2Smrg  *(put++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
633627f7eb2Smrg  if (ft == FMT_F
634627f7eb2Smrg	  && (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED
635627f7eb2Smrg	      || dtp->u.p.current_unit->round_status == ROUND_PROCDEFINED))
636627f7eb2Smrg    digits++;
637627f7eb2Smrg
638627f7eb2Smrg  /* Set leading zeros after the decimal point.  */
639627f7eb2Smrg  if (nzero > 0)
640627f7eb2Smrg    {
641627f7eb2Smrg      for (i = 0; i < nzero; i++)
642627f7eb2Smrg	*(put++) = '0';
643627f7eb2Smrg    }
644627f7eb2Smrg
645627f7eb2Smrg  /* Set digits after the decimal point, padding with zeros.  */
646627f7eb2Smrg  if (ndigits >= 0 && nafter > 0)
647627f7eb2Smrg    {
648627f7eb2Smrg      if (nafter > ndigits)
649627f7eb2Smrg	i = ndigits;
650627f7eb2Smrg      else
651627f7eb2Smrg	i = nafter;
652627f7eb2Smrg
653627f7eb2Smrg      if (i > 0)
654627f7eb2Smrg	memcpy (put, digits, i);
655627f7eb2Smrg      while (i < nafter)
656627f7eb2Smrg	put[i++] = '0';
657627f7eb2Smrg
658627f7eb2Smrg      digits += i;
659627f7eb2Smrg      ndigits -= i;
660627f7eb2Smrg      put += nafter;
661627f7eb2Smrg    }
662627f7eb2Smrg
663627f7eb2Smrg  /* Set the exponent.  */
664627f7eb2Smrg  if (expchar && !(dtp->u.p.g0_no_blanks && e == 0))
665627f7eb2Smrg    {
666627f7eb2Smrg      if (expchar != ' ')
667627f7eb2Smrg	{
668627f7eb2Smrg	  *(put++) = expchar;
669627f7eb2Smrg	  edigits--;
670627f7eb2Smrg	}
671627f7eb2Smrg      snprintf (buffer, size, "%+0*d", edigits, e);
672627f7eb2Smrg      memcpy (put, buffer, edigits);
673627f7eb2Smrg      put += edigits;
674627f7eb2Smrg    }
675627f7eb2Smrg
676627f7eb2Smrg  if (dtp->u.p.no_leading_blank)
677627f7eb2Smrg    {
678627f7eb2Smrg      memset (put , ' ' , nblanks);
679627f7eb2Smrg      dtp->u.p.no_leading_blank = 0;
680627f7eb2Smrg      put += nblanks;
681627f7eb2Smrg    }
682627f7eb2Smrg
683627f7eb2Smrg  if (npad > 0 && !dtp->u.p.g0_no_blanks)
684627f7eb2Smrg    {
685627f7eb2Smrg      memset (put , ' ' , npad);
686627f7eb2Smrg      put += npad;
687627f7eb2Smrg    }
688627f7eb2Smrg
689627f7eb2Smrg  /* NULL terminate the string.  */
690627f7eb2Smrg  *put = '\0';
691627f7eb2Smrg
692627f7eb2Smrg  return;
693627f7eb2Smrg}
694627f7eb2Smrg
695627f7eb2Smrg
696627f7eb2Smrg/* Write "Infinite" or "Nan" as appropriate for the given format.  */
697627f7eb2Smrg
698627f7eb2Smrgstatic void
699627f7eb2Smrgbuild_infnan_string (st_parameter_dt *dtp, const fnode *f, int isnan_flag,
700627f7eb2Smrg		    int sign_bit, char *p, size_t *len)
701627f7eb2Smrg{
702627f7eb2Smrg  char fin;
703627f7eb2Smrg  int nb = 0;
704627f7eb2Smrg  sign_t sign;
705627f7eb2Smrg  int mark;
706627f7eb2Smrg
707627f7eb2Smrg  if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
708627f7eb2Smrg    {
709627f7eb2Smrg      sign = calculate_sign (dtp, sign_bit);
710627f7eb2Smrg      mark = (sign == S_PLUS || sign == S_MINUS) ? 8 : 7;
711627f7eb2Smrg
712627f7eb2Smrg      nb =  f->u.real.w;
713627f7eb2Smrg      *len = nb;
714627f7eb2Smrg
715627f7eb2Smrg      /* If the field width is zero, the processor must select a width
716627f7eb2Smrg	 not zero.  4 is chosen to allow output of '-Inf' or '+Inf' */
717627f7eb2Smrg
718627f7eb2Smrg      if ((nb == 0) || dtp->u.p.g0_no_blanks)
719627f7eb2Smrg	{
720627f7eb2Smrg	  if (isnan_flag)
721627f7eb2Smrg	    nb = 3;
722627f7eb2Smrg	  else
723627f7eb2Smrg	    nb = (sign == S_PLUS || sign == S_MINUS) ? 4 : 3;
724627f7eb2Smrg	  *len = nb;
725627f7eb2Smrg	}
726627f7eb2Smrg
727627f7eb2Smrg      p[*len] = '\0';
728627f7eb2Smrg      if (nb < 3)
729627f7eb2Smrg	{
730627f7eb2Smrg	  memset (p, '*', nb);
731627f7eb2Smrg	  return;
732627f7eb2Smrg	}
733627f7eb2Smrg
734627f7eb2Smrg      memset(p, ' ', nb);
735627f7eb2Smrg
736627f7eb2Smrg      if (!isnan_flag)
737627f7eb2Smrg	{
738627f7eb2Smrg	  if (sign_bit)
739627f7eb2Smrg	    {
740627f7eb2Smrg	      /* If the sign is negative and the width is 3, there is
741627f7eb2Smrg		 insufficient room to output '-Inf', so output asterisks */
742627f7eb2Smrg	      if (nb == 3)
743627f7eb2Smrg		{
744627f7eb2Smrg		  memset (p, '*', nb);
745627f7eb2Smrg		  return;
746627f7eb2Smrg		}
747627f7eb2Smrg	      /* The negative sign is mandatory */
748627f7eb2Smrg	      fin = '-';
749627f7eb2Smrg	    }
750627f7eb2Smrg	  else
751627f7eb2Smrg	    /* The positive sign is optional, but we output it for
752627f7eb2Smrg	       consistency */
753627f7eb2Smrg	    fin = '+';
754627f7eb2Smrg
755627f7eb2Smrg	  if (nb > mark)
756627f7eb2Smrg	    /* We have room, so output 'Infinity' */
757627f7eb2Smrg	    memcpy(p + nb - 8, "Infinity", 8);
758627f7eb2Smrg	  else
759627f7eb2Smrg	    /* For the case of width equals 8, there is not enough room
760627f7eb2Smrg	       for the sign and 'Infinity' so we go with 'Inf' */
761627f7eb2Smrg	    memcpy(p + nb - 3, "Inf", 3);
762627f7eb2Smrg
763627f7eb2Smrg	  if (sign == S_PLUS || sign == S_MINUS)
764627f7eb2Smrg	    {
765627f7eb2Smrg	      if (nb < 9 && nb > 3)
766627f7eb2Smrg		p[nb - 4] = fin;  /* Put the sign in front of Inf */
767627f7eb2Smrg	      else if (nb > 8)
768627f7eb2Smrg		p[nb - 9] = fin;  /* Put the sign in front of Infinity */
769627f7eb2Smrg	    }
770627f7eb2Smrg	}
771627f7eb2Smrg      else
772627f7eb2Smrg	memcpy(p + nb - 3, "NaN", 3);
773627f7eb2Smrg    }
774627f7eb2Smrg}
775627f7eb2Smrg
776627f7eb2Smrg
777627f7eb2Smrg/* Returns the value of 10**d.  */
778627f7eb2Smrg
779627f7eb2Smrg#define CALCULATE_EXP(x) \
780627f7eb2Smrgstatic GFC_REAL_ ## x \
781627f7eb2Smrgcalculate_exp_ ## x  (int d)\
782627f7eb2Smrg{\
783627f7eb2Smrg  int i;\
784627f7eb2Smrg  GFC_REAL_ ## x r = 1.0;\
785627f7eb2Smrg  for (i = 0; i< (d >= 0 ? d : -d); i++)\
786627f7eb2Smrg    r *= 10;\
787627f7eb2Smrg  r = (d >= 0) ? r : 1.0 / r;\
788627f7eb2Smrg  return r;\
789627f7eb2Smrg}
790627f7eb2Smrg
791627f7eb2SmrgCALCULATE_EXP(4)
792627f7eb2Smrg
793627f7eb2SmrgCALCULATE_EXP(8)
794627f7eb2Smrg
795627f7eb2Smrg#ifdef HAVE_GFC_REAL_10
796627f7eb2SmrgCALCULATE_EXP(10)
797627f7eb2Smrg#endif
798627f7eb2Smrg
799627f7eb2Smrg#ifdef HAVE_GFC_REAL_16
800627f7eb2SmrgCALCULATE_EXP(16)
801627f7eb2Smrg#endif
802627f7eb2Smrg#undef CALCULATE_EXP
803627f7eb2Smrg
804627f7eb2Smrg
805627f7eb2Smrg/* Define macros to build code for format_float.  */
806627f7eb2Smrg
807627f7eb2Smrg  /* Note: Before output_float is called, snprintf is used to print to buffer the
808627f7eb2Smrg     number in the format +D.DDDDe+ddd.
809627f7eb2Smrg
810627f7eb2Smrg     #   The result will always contain a decimal point, even if no
811627f7eb2Smrg	 digits follow it
812627f7eb2Smrg
813627f7eb2Smrg     -   The converted value is to be left adjusted on the field boundary
814627f7eb2Smrg
815627f7eb2Smrg     +   A sign (+ or -) always be placed before a number
816627f7eb2Smrg
817627f7eb2Smrg     *   prec is used as the precision
818627f7eb2Smrg
819627f7eb2Smrg     e format: [-]d.ddde±dd where there is one digit before the
820627f7eb2Smrg       decimal-point character and the number of digits after it is
821627f7eb2Smrg       equal to the precision. The exponent always contains at least two
822627f7eb2Smrg       digits; if the value is zero, the exponent is 00.  */
823627f7eb2Smrg
824627f7eb2Smrg
825627f7eb2Smrg#define TOKENPASTE(x, y) TOKENPASTE2(x, y)
826627f7eb2Smrg#define TOKENPASTE2(x, y) x ## y
827627f7eb2Smrg
828627f7eb2Smrg#define DTOA(suff,prec,val) TOKENPASTE(DTOA2,suff)(prec,val)
829627f7eb2Smrg
830627f7eb2Smrg#define DTOA2(prec,val) \
831627f7eb2Smrgsnprintf (buffer, size, "%+-#.*e", (prec), (val))
832627f7eb2Smrg
833627f7eb2Smrg#define DTOA2L(prec,val) \
834627f7eb2Smrgsnprintf (buffer, size, "%+-#.*Le", (prec), (val))
835627f7eb2Smrg
836627f7eb2Smrg
837627f7eb2Smrg#if defined(GFC_REAL_16_IS_FLOAT128)
838627f7eb2Smrg#define DTOA2Q(prec,val) \
839627f7eb2Smrgquadmath_snprintf (buffer, size, "%+-#.*Qe", (prec), (val))
840627f7eb2Smrg#endif
841627f7eb2Smrg
842627f7eb2Smrg#define FDTOA(suff,prec,val) TOKENPASTE(FDTOA2,suff)(prec,val)
843627f7eb2Smrg
844627f7eb2Smrg/* For F format, we print to the buffer with f format.  */
845627f7eb2Smrg#define FDTOA2(prec,val) \
846627f7eb2Smrgsnprintf (buffer, size, "%+-#.*f", (prec), (val))
847627f7eb2Smrg
848627f7eb2Smrg#define FDTOA2L(prec,val) \
849627f7eb2Smrgsnprintf (buffer, size, "%+-#.*Lf", (prec), (val))
850627f7eb2Smrg
851627f7eb2Smrg
852627f7eb2Smrg#if defined(GFC_REAL_16_IS_FLOAT128)
853627f7eb2Smrg#define FDTOA2Q(prec,val) \
854627f7eb2Smrgquadmath_snprintf (buffer, size, "%+-#.*Qf", \
855627f7eb2Smrg			     (prec), (val))
856627f7eb2Smrg#endif
857627f7eb2Smrg
858627f7eb2Smrg
859627f7eb2Smrg/* EN format is tricky since the number of significant digits depends
860627f7eb2Smrg   on the magnitude.  Solve it by first printing a temporary value and
861627f7eb2Smrg   figure out the number of significant digits from the printed
862627f7eb2Smrg   exponent.  Values y, 0.95*10.0**e <= y <10.0**e, are rounded to
863627f7eb2Smrg   10.0**e even when the final result will not be rounded to 10.0**e.
864627f7eb2Smrg   For these values the exponent returned by atoi has to be decremented
865627f7eb2Smrg   by one. The values y in the ranges
866627f7eb2Smrg       (1000.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*(n+1))
867627f7eb2Smrg        (100.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+2)
868627f7eb2Smrg         (10.0-0.5*10.0**(-d))*10.0**(3*n) <= y < 10.0*(3*n+1)
869627f7eb2Smrg   are correctly rounded respectively to 1.0...0*10.0*(3*(n+1)),
870627f7eb2Smrg   100.0...0*10.0*(3*n), and 10.0...0*10.0*(3*n), where 0...0
871627f7eb2Smrg   represents d zeroes, by the lines 279 to 297. */
872627f7eb2Smrg#define EN_PREC(x,y)\
873627f7eb2Smrg{\
874627f7eb2Smrg    volatile GFC_REAL_ ## x tmp, one = 1.0;\
875627f7eb2Smrg    tmp = * (GFC_REAL_ ## x *)source;\
876627f7eb2Smrg    if (isfinite (tmp))\
877627f7eb2Smrg      {\
878627f7eb2Smrg	nprinted = DTOA(y,0,tmp);\
879627f7eb2Smrg	int e = atoi (&buffer[4]);\
880627f7eb2Smrg	if (buffer[1] == '1')\
881627f7eb2Smrg	  {\
882627f7eb2Smrg	    tmp = (calculate_exp_ ## x (-e)) * tmp;\
883627f7eb2Smrg	    tmp = one - (tmp < 0 ? -tmp : tmp);\
884627f7eb2Smrg	    if (tmp > 0)\
885627f7eb2Smrg	      e = e - 1;\
886627f7eb2Smrg	  }\
887627f7eb2Smrg	nbefore = e%3;\
888627f7eb2Smrg	if (nbefore < 0)\
889627f7eb2Smrg	  nbefore = 3 + nbefore;\
890627f7eb2Smrg      }\
891627f7eb2Smrg    else\
892627f7eb2Smrg      nprinted = -1;\
893627f7eb2Smrg}\
894627f7eb2Smrg
895627f7eb2Smrgstatic int
896627f7eb2Smrgdetermine_en_precision (st_parameter_dt *dtp, const fnode *f,
897627f7eb2Smrg			const char *source, int len)
898627f7eb2Smrg{
899627f7eb2Smrg  int nprinted;
900627f7eb2Smrg  char buffer[10];
901627f7eb2Smrg  const size_t size = 10;
902627f7eb2Smrg  int nbefore; /* digits before decimal point - 1.  */
903627f7eb2Smrg
904627f7eb2Smrg  switch (len)
905627f7eb2Smrg    {
906627f7eb2Smrg    case 4:
907627f7eb2Smrg      EN_PREC(4,)
908627f7eb2Smrg      break;
909627f7eb2Smrg
910627f7eb2Smrg    case 8:
911627f7eb2Smrg      EN_PREC(8,)
912627f7eb2Smrg      break;
913627f7eb2Smrg
914627f7eb2Smrg#ifdef HAVE_GFC_REAL_10
915627f7eb2Smrg    case 10:
916627f7eb2Smrg      EN_PREC(10,L)
917627f7eb2Smrg      break;
918627f7eb2Smrg#endif
919627f7eb2Smrg#ifdef HAVE_GFC_REAL_16
920627f7eb2Smrg    case 16:
921627f7eb2Smrg# ifdef GFC_REAL_16_IS_FLOAT128
922627f7eb2Smrg      EN_PREC(16,Q)
923627f7eb2Smrg# else
924627f7eb2Smrg      EN_PREC(16,L)
925627f7eb2Smrg# endif
926627f7eb2Smrg      break;
927627f7eb2Smrg#endif
928627f7eb2Smrg    default:
929627f7eb2Smrg      internal_error (NULL, "bad real kind");
930627f7eb2Smrg    }
931627f7eb2Smrg
932627f7eb2Smrg  if (nprinted == -1)
933627f7eb2Smrg    return -1;
934627f7eb2Smrg
935627f7eb2Smrg  int prec = f->u.real.d + nbefore;
936627f7eb2Smrg  if (dtp->u.p.current_unit->round_status != ROUND_UNSPECIFIED
937627f7eb2Smrg      && dtp->u.p.current_unit->round_status != ROUND_PROCDEFINED)
938627f7eb2Smrg    prec += 2 * len + 4;
939627f7eb2Smrg  return prec;
940627f7eb2Smrg}
941627f7eb2Smrg
942627f7eb2Smrg
943627f7eb2Smrg/* Generate corresponding I/O format. and output.
944627f7eb2Smrg   The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
945627f7eb2Smrg   LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
946627f7eb2Smrg
947627f7eb2Smrg   Data Magnitude                              Equivalent Conversion
948627f7eb2Smrg   0< m < 0.1-0.5*10**(-d-1)                   Ew.d[Ee]
949627f7eb2Smrg   m = 0                                       F(w-n).(d-1), n' '
950627f7eb2Smrg   0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d)     F(w-n).d, n' '
951627f7eb2Smrg   1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1)      F(w-n).(d-1), n' '
952627f7eb2Smrg   10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2)  F(w-n).(d-2), n' '
953627f7eb2Smrg   ................                           ..........
954627f7eb2Smrg   10**(d-1)-0.5*10**(-1)<= m <10**d-0.5       F(w-n).0,n(' ')
955627f7eb2Smrg   m >= 10**d-0.5                              Ew.d[Ee]
956627f7eb2Smrg
957627f7eb2Smrg   notes: for Gw.d ,  n' ' means 4 blanks
958627f7eb2Smrg	  for Gw.dEe, n' ' means e+2 blanks
959627f7eb2Smrg	  for rounding modes adjustment, r, See Fortran F2008 10.7.5.2.2
960627f7eb2Smrg	  the asm volatile is required for 32-bit x86 platforms.  */
961627f7eb2Smrg#define FORMAT_FLOAT(x,y)\
962627f7eb2Smrg{\
963627f7eb2Smrg  int npad = 0;\
964627f7eb2Smrg  GFC_REAL_ ## x m;\
965627f7eb2Smrg  m = * (GFC_REAL_ ## x *)source;\
966627f7eb2Smrg  sign_bit = signbit (m);\
967627f7eb2Smrg  if (!isfinite (m))\
968627f7eb2Smrg    { \
969627f7eb2Smrg      build_infnan_string (dtp, f, isnan (m), sign_bit, result, res_len);\
970627f7eb2Smrg      return;\
971627f7eb2Smrg    }\
972627f7eb2Smrg  m = sign_bit ? -m : m;\
973627f7eb2Smrg  zero_flag = (m == 0.0);\
974627f7eb2Smrg  if (f->format == FMT_G)\
975627f7eb2Smrg    {\
976627f7eb2Smrg      int e = f->u.real.e;\
977627f7eb2Smrg      int d = f->u.real.d;\
978627f7eb2Smrg      int w = f->u.real.w;\
979627f7eb2Smrg      fnode newf;\
980627f7eb2Smrg      GFC_REAL_ ## x exp_d, r = 0.5, r_sc;\
981627f7eb2Smrg      int low, high, mid;\
982627f7eb2Smrg      int ubound, lbound;\
983627f7eb2Smrg      int save_scale_factor;\
984627f7eb2Smrg      volatile GFC_REAL_ ## x temp;\
985627f7eb2Smrg      save_scale_factor = dtp->u.p.scale_factor;\
986*4c3eb207Smrg      if (w == DEFAULT_WIDTH)\
987*4c3eb207Smrg	{\
988*4c3eb207Smrg	  w = default_width;\
989*4c3eb207Smrg	  d = precision;\
990*4c3eb207Smrg	}\
991*4c3eb207Smrg      /* The switch between FMT_E and FMT_F is based on the absolute value.  \
992*4c3eb207Smrg         Set r=0 for rounding toward zero and r = 1 otherwise.  \
993*4c3eb207Smrg	 If (exp_d - m) == 1 there is no rounding needed.  */\
994627f7eb2Smrg      switch (dtp->u.p.current_unit->round_status)\
995627f7eb2Smrg	{\
996627f7eb2Smrg	  case ROUND_ZERO:\
997*4c3eb207Smrg	    r = 0.0;\
998627f7eb2Smrg	    break;\
999627f7eb2Smrg	  case ROUND_UP:\
1000*4c3eb207Smrg	    r = sign_bit ? 0.0 : 1.0;\
1001627f7eb2Smrg	    break;\
1002627f7eb2Smrg	  case ROUND_DOWN:\
1003*4c3eb207Smrg	    r = sign_bit ? 1.0 : 0.0;\
1004627f7eb2Smrg	    break;\
1005627f7eb2Smrg	  default:\
1006627f7eb2Smrg	    break;\
1007627f7eb2Smrg	}\
1008627f7eb2Smrg      exp_d = calculate_exp_ ## x (d);\
1009627f7eb2Smrg      r_sc = (1 - r / exp_d);\
1010627f7eb2Smrg      temp = 0.1 * r_sc;\
1011*4c3eb207Smrg      if ((m > 0.0 && ((m < temp) || (r < 1 && r >= (exp_d - m))\
1012*4c3eb207Smrg				  || (r == 1 && 1 > (exp_d - m))))\
1013627f7eb2Smrg	  || ((m == 0.0) && !(compile_options.allow_std\
1014627f7eb2Smrg			      & (GFC_STD_F2003 | GFC_STD_F2008)))\
1015627f7eb2Smrg	  ||  d == 0)\
1016627f7eb2Smrg	{ \
1017627f7eb2Smrg	  newf.format = FMT_E;\
1018627f7eb2Smrg	  newf.u.real.w = w;\
1019627f7eb2Smrg	  newf.u.real.d = d - comp_d;\
1020627f7eb2Smrg	  newf.u.real.e = e;\
1021627f7eb2Smrg	  npad = 0;\
1022627f7eb2Smrg	  precision = determine_precision (dtp, &newf, x);\
1023627f7eb2Smrg	  nprinted = DTOA(y,precision,m);\
1024627f7eb2Smrg	}\
1025627f7eb2Smrg      else \
1026627f7eb2Smrg	{\
1027627f7eb2Smrg	  mid = 0;\
1028627f7eb2Smrg	  low = 0;\
1029627f7eb2Smrg	  high = d + 1;\
1030627f7eb2Smrg	  lbound = 0;\
1031627f7eb2Smrg	  ubound = d + 1;\
1032627f7eb2Smrg	  while (low <= high)\
1033627f7eb2Smrg	    {\
1034627f7eb2Smrg	      mid = (low + high) / 2;\
1035627f7eb2Smrg	      temp = (calculate_exp_ ## x (mid - 1) * r_sc);\
1036627f7eb2Smrg	      if (m < temp)\
1037627f7eb2Smrg		{ \
1038627f7eb2Smrg		  ubound = mid;\
1039627f7eb2Smrg		  if (ubound == lbound + 1)\
1040627f7eb2Smrg		    break;\
1041627f7eb2Smrg		  high = mid - 1;\
1042627f7eb2Smrg		}\
1043627f7eb2Smrg	      else if (m > temp)\
1044627f7eb2Smrg		{ \
1045627f7eb2Smrg		  lbound = mid;\
1046627f7eb2Smrg		  if (ubound == lbound + 1)\
1047627f7eb2Smrg		    { \
1048627f7eb2Smrg		      mid ++;\
1049627f7eb2Smrg		      break;\
1050627f7eb2Smrg		    }\
1051627f7eb2Smrg		  low = mid + 1;\
1052627f7eb2Smrg		}\
1053627f7eb2Smrg	      else\
1054627f7eb2Smrg		{\
1055627f7eb2Smrg		  mid++;\
1056627f7eb2Smrg		  break;\
1057627f7eb2Smrg		}\
1058627f7eb2Smrg	    }\
1059627f7eb2Smrg	  npad = e <= 0 ? 4 : e + 2;\
1060627f7eb2Smrg	  npad = npad >= w ? w - 1 : npad;\
1061627f7eb2Smrg	  npad = dtp->u.p.g0_no_blanks ? 0 : npad;\
1062627f7eb2Smrg	  newf.format = FMT_F;\
1063627f7eb2Smrg	  newf.u.real.w = w - npad;\
1064627f7eb2Smrg	  newf.u.real.d = m == 0.0 ? d - 1 : -(mid - d - 1) ;\
1065627f7eb2Smrg	  dtp->u.p.scale_factor = 0;\
1066627f7eb2Smrg	  precision = determine_precision (dtp, &newf, x);\
1067627f7eb2Smrg	  nprinted = FDTOA(y,precision,m);\
1068627f7eb2Smrg	}\
1069627f7eb2Smrg      build_float_string (dtp, &newf, buffer, size, nprinted, precision,\
1070*4c3eb207Smrg				   sign_bit, zero_flag, npad, default_width,\
1071*4c3eb207Smrg				   result, res_len);\
1072627f7eb2Smrg      dtp->u.p.scale_factor = save_scale_factor;\
1073627f7eb2Smrg    }\
1074627f7eb2Smrg  else\
1075627f7eb2Smrg    {\
1076627f7eb2Smrg      if (f->format == FMT_F)\
1077627f7eb2Smrg	nprinted = FDTOA(y,precision,m);\
1078627f7eb2Smrg      else\
1079627f7eb2Smrg	nprinted = DTOA(y,precision,m);\
1080627f7eb2Smrg      build_float_string (dtp, f, buffer, size, nprinted, precision,\
1081*4c3eb207Smrg				   sign_bit, zero_flag, npad, default_width,\
1082*4c3eb207Smrg				   result, res_len);\
1083627f7eb2Smrg    }\
1084627f7eb2Smrg}\
1085627f7eb2Smrg
1086627f7eb2Smrg/* Output a real number according to its format.  */
1087627f7eb2Smrg
1088627f7eb2Smrg
1089627f7eb2Smrgstatic void
1090627f7eb2Smrgget_float_string (st_parameter_dt *dtp, const fnode *f, const char *source,
1091627f7eb2Smrg		  int kind, int comp_d, char *buffer, int precision,
1092627f7eb2Smrg		  size_t size, char *result, size_t *res_len)
1093627f7eb2Smrg{
1094627f7eb2Smrg  int sign_bit, nprinted;
1095627f7eb2Smrg  bool zero_flag;
1096*4c3eb207Smrg  int default_width = 0;
1097*4c3eb207Smrg
1098*4c3eb207Smrg  if (f->u.real.w == DEFAULT_WIDTH)
1099*4c3eb207Smrg    /* This codepath can only be reached with -fdec-format-defaults. The default
1100*4c3eb207Smrg     * values are based on those used in the Oracle Fortran compiler.
1101*4c3eb207Smrg     */
1102*4c3eb207Smrg    {
1103*4c3eb207Smrg      default_width = default_width_for_float (kind);
1104*4c3eb207Smrg      precision = default_precision_for_float (kind);
1105*4c3eb207Smrg    }
1106627f7eb2Smrg
1107627f7eb2Smrg  switch (kind)
1108627f7eb2Smrg    {
1109627f7eb2Smrg    case 4:
1110627f7eb2Smrg      FORMAT_FLOAT(4,)
1111627f7eb2Smrg      break;
1112627f7eb2Smrg
1113627f7eb2Smrg    case 8:
1114627f7eb2Smrg      FORMAT_FLOAT(8,)
1115627f7eb2Smrg      break;
1116627f7eb2Smrg
1117627f7eb2Smrg#ifdef HAVE_GFC_REAL_10
1118627f7eb2Smrg    case 10:
1119627f7eb2Smrg      FORMAT_FLOAT(10,L)
1120627f7eb2Smrg      break;
1121627f7eb2Smrg#endif
1122627f7eb2Smrg#ifdef HAVE_GFC_REAL_16
1123627f7eb2Smrg    case 16:
1124627f7eb2Smrg# ifdef GFC_REAL_16_IS_FLOAT128
1125627f7eb2Smrg      FORMAT_FLOAT(16,Q)
1126627f7eb2Smrg# else
1127627f7eb2Smrg      FORMAT_FLOAT(16,L)
1128627f7eb2Smrg# endif
1129627f7eb2Smrg      break;
1130627f7eb2Smrg#endif
1131627f7eb2Smrg    default:
1132627f7eb2Smrg      internal_error (NULL, "bad real kind");
1133627f7eb2Smrg    }
1134627f7eb2Smrg  return;
1135627f7eb2Smrg}
1136