1 /* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
4 This file is part of the GNU Fortran 95 runtime library (libgfortran).
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Libgfortran; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
26 #include "libgfortran.h"
30 #define star_fill(p, n) memset(p, '*', n)
34 { SIGN_NONE
, SIGN_MINUS
, SIGN_PLUS
}
39 write_a (fnode
* f
, const char *source
, int len
)
44 wlen
= f
->u
.string
.length
< 0 ? len
: f
->u
.string
.length
;
46 p
= write_block (wlen
);
51 memcpy (p
, source
, wlen
);
54 memset (p
, ' ', wlen
- len
);
55 memcpy (p
+ wlen
- len
, source
, len
);
60 extract_int (const void *p
, int len
)
70 i
= *((const int8_t *) p
);
73 i
= *((const int16_t *) p
);
76 i
= *((const int32_t *) p
);
79 i
= *((const int64_t *) p
);
82 internal_error ("bad integer kind");
89 extract_real (const void *p
, int len
)
95 i
= *((const float *) p
);
98 i
= *((const double *) p
);
101 internal_error ("bad real kind");
108 /* Given a flag that indicate if a value is negative or not, return a
109 sign_t that gives the sign that we need to produce. */
112 calculate_sign (int negative_flag
)
114 sign_t s
= SIGN_NONE
;
119 switch (g
.sign_status
)
128 s
= options
.optional_plus
? SIGN_PLUS
: SIGN_NONE
;
136 /* Returns the value of 10**d. */
139 calculate_exp (int d
)
144 for (i
= 0; i
< (d
>= 0 ? d
: -d
); i
++)
147 r
= (d
>= 0) ? r
: 1.0 / r
;
153 /* Generate corresponding I/O format for FMT_G output.
154 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
155 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
157 Data Magnitude Equivalent Conversion
158 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
159 m = 0 F(w-n).(d-1), n' '
160 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
161 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
162 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
163 ................ ..........
164 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
165 m >= 10**d-0.5 Ew.d[Ee]
167 notes: for Gw.d , n' ' means 4 blanks
168 for Gw.dEe, n' ' means e+2 blanks */
171 calculate_G_format (fnode
*f
, double value
, int len
, int *num_blank
)
181 newf
= get_mem (sizeof (fnode
));
183 /* Absolute value. */
184 m
= (value
> 0.0) ? value
: -value
;
186 /* In case of the two data magnitude ranges,
187 generate E editing, Ew.d[Ee]. */
188 exp_d
= calculate_exp (d
);
189 if ((m
> 0.0 && m
< 0.1 - 0.05 / (double) exp_d
)
190 || (m
>= (double) exp_d
- 0.5 ))
192 newf
->format
= FMT_E
;
200 /* Use binary search to find the data magnitude range. */
210 mid
= (low
+ high
) / 2;
212 /* 0.1 * 10**mid - 0.5 * 10**(mid-d-1) */
213 temp
= 0.1 * calculate_exp (mid
) - 0.5 * calculate_exp (mid
- d
- 1);
218 if (ubound
== lbound
+ 1)
225 if (ubound
== lbound
+ 1)
236 /* Pad with blanks where the exponent would be. */
242 /* Generate the F editing. F(w-n).(-(mid-d-1)), n' '. */
243 newf
->format
= FMT_F
;
244 newf
->u
.real
.w
= f
->u
.real
.w
- *num_blank
;
248 newf
->u
.real
.d
= d
- 1;
250 newf
->u
.real
.d
= - (mid
- d
- 1);
252 /* For F editing, the scale factor is ignored. */
258 /* Output a real number according to its format which is FMT_G free. */
261 output_float (fnode
*f
, double value
, int len
)
263 /* This must be large enough to accurately hold any value. */
274 /* Number of digits before the decimal point. */
276 /* Number of zeros after the decimal point. */
278 /* Number of digits after the decimal point. */
289 /* We should always know the field width and precision. */
291 internal_error ("Uspecified precision");
293 /* Use sprintf to print the number in the format +D.DDDDe+ddd
294 For an N digit exponent, this gives us (32-6)-N digits after the
295 decimal point, plus another one before the decimal point. */
296 sign
= calculate_sign (value
< 0.0);
300 /* Printf always prints at least two exponent digits. */
305 edigits
= 1 + (int) log10 (fabs(log10 (value
)));
310 if (ft
== FMT_F
|| ft
== FMT_EN
311 || ((ft
== FMT_D
|| ft
== FMT_E
) && g
.scale_factor
!= 0))
313 /* Always convert at full precision to avoid double rounding. */
314 ndigits
= 27 - edigits
;
318 /* We know the number of digits, so can let printf do the rounding
324 if (ndigits
> 27 - edigits
)
325 ndigits
= 27 - edigits
;
328 sprintf (buffer
, "%+-#31.*e", ndigits
- 1, value
);
330 /* Check the resulting string has punctuation in the correct places. */
331 if (buffer
[2] != '.' || buffer
[ndigits
+ 2] != 'e')
332 internal_error ("printf is broken");
334 /* Read the exponent back in. */
335 e
= atoi (&buffer
[ndigits
+ 3]) + 1;
337 /* Make sure zero comes out as 0.0e0. */
341 /* Normalize the fractional component. */
342 buffer
[2] = buffer
[1];
345 /* Figure out where to place the decimal point. */
349 nbefore
= e
+ g
.scale_factor
;
380 nafter
= (d
- i
) + 1;
396 /* The exponent must be a multiple of three, with 1-3 digits before
397 the decimal point. */
405 nbefore
= 3 - nbefore
;
423 /* Should never happen. */
424 internal_error ("Unexpected format token");
427 /* Round the value. */
428 if (nbefore
+ nafter
== 0)
430 else if (nbefore
+ nafter
< ndigits
)
432 ndigits
= nbefore
+ nafter
;
434 if (digits
[i
] >= '5')
436 /* Propagate the carry. */
437 for (i
--; i
>= 0; i
--)
439 if (digits
[i
] != '9')
449 /* The carry overflowed. Fortunately we have some spare space
450 at the start of the buffer. We may discard some digits, but
451 this is ok because we already know they are zero. */
464 else if (ft
== FMT_EN
)
479 /* Calculate the format of the exponent field. */
483 for (i
= abs (e
); i
>= 10; i
/= 10)
488 /* Width not specified. Must be no more than 3 digits. */
489 if (e
> 999 || e
< -999)
494 if (e
> 99 || e
< -99)
500 /* Exponent width specified, check it is wide enough. */
501 if (edigits
> f
->u
.real
.e
)
504 edigits
= f
->u
.real
.e
+ 2;
510 /* Pick a field size if none was specified. */
512 w
= nbefore
+ nzero
+ nafter
+ 2;
514 /* Create the ouput buffer. */
515 out
= write_block (w
);
519 /* Zero values always output as positive, even if the value was negative
521 for (i
= 0; i
< ndigits
; i
++)
523 if (digits
[i
] != '0')
527 sign
= calculate_sign (0);
529 /* Work out how much padding is needed. */
530 nblanks
= w
- (nbefore
+ nzero
+ nafter
+ edigits
+ 1);
531 if (sign
!= SIGN_NONE
)
534 /* Check the value fits in the specified field width. */
535 if (nblanks
< 0 || edigits
== -1)
541 /* See if we have space for a zero before the decimal point. */
542 if (nbefore
== 0 && nblanks
> 0)
550 /* Padd to full field width. */
553 memset (out
, ' ', nblanks
);
557 /* Output the initial sign (if any). */
558 if (sign
== SIGN_PLUS
)
560 else if (sign
== SIGN_MINUS
)
563 /* Output an optional leading zero. */
567 /* Output the part before the decimal point, padding with zeros. */
570 if (nbefore
> ndigits
)
575 memcpy (out
, digits
, i
);
583 /* Output the decimal point. */
586 /* Output leading zeros after the decimal point. */
589 for (i
= 0; i
< nzero
; i
++)
593 /* Output digits after the decimal point, padding with zeros. */
596 if (nafter
> ndigits
)
601 memcpy (out
, digits
, i
);
610 /* Output the exponent. */
618 snprintf (buffer
, 32, "%+0*d", edigits
, e
);
619 memcpy (out
, buffer
, edigits
);
625 write_l (fnode
* f
, char *source
, int len
)
630 p
= write_block (f
->u
.w
);
634 memset (p
, ' ', f
->u
.w
- 1);
635 n
= extract_int (source
, len
);
636 p
[f
->u
.w
- 1] = (n
) ? 'T' : 'F';
639 /* Output a real number according to its format. */
642 write_float (fnode
*f
, const char *source
, int len
)
649 n
= extract_real (source
, len
);
651 if (f
->format
!= FMT_B
&& f
->format
!= FMT_O
&& f
->format
!= FMT_Z
)
657 p
= write_block (nb
);
674 memcpy(p
+ nb
- 8, "Infinity", 8);
676 memcpy(p
+ nb
- 3, "Inf", 3);
677 if (nb
< 8 && nb
> 3)
683 memcpy(p
+ nb
- 3, "NaN", 3);
688 if (f
->format
!= FMT_G
)
690 output_float (f
, n
, len
);
694 f2
= calculate_G_format(f
, n
, len
, &nb
);
695 output_float (f2
, n
, len
);
701 p
= write_block (nb
);
709 write_int (fnode
*f
, const char *source
, int len
, char *(*conv
) (uint64_t))
713 int w
, m
, digits
, nzero
, nblank
;
719 n
= extract_int (source
, len
);
723 if (m
== 0 && n
== 0)
747 /* Select a width if none was specified. The idea here is to always
751 w
= ((digits
< m
) ? m
: digits
);
761 /* See if things will work. */
763 nblank
= w
- (nzero
+ digits
);
771 memset (p
, ' ', nblank
);
774 memset (p
, '0', nzero
);
777 memcpy (p
, q
, digits
);
784 write_decimal (fnode
*f
, const char *source
, int len
, char *(*conv
) (int64_t))
787 int w
, m
, digits
, nsign
, nzero
, nblank
;
794 n
= extract_int (source
, len
);
798 if (m
== 0 && n
== 0)
811 sign
= calculate_sign (n
< 0);
815 nsign
= sign
== SIGN_NONE
? 0 : 1;
820 /* Select a width if none was specified. The idea here is to always
824 w
= ((digits
< m
) ? m
: digits
) + nsign
;
834 /* See if things will work. */
836 nblank
= w
- (nsign
+ nzero
+ digits
);
844 memset (p
, ' ', nblank
);
859 memset (p
, '0', nzero
);
862 memcpy (p
, q
, digits
);
869 /* Convert unsigned octal to ascii. */
883 p
= scratch
+ sizeof (SCRATCH_SIZE
) - 1;
897 /* Convert unsigned binary to ascii. */
911 p
= scratch
+ sizeof (SCRATCH_SIZE
) - 1;
916 *p
-- = '0' + (n
& 1);
925 write_i (fnode
* f
, const char *p
, int len
)
928 write_decimal (f
, p
, len
, (void *) itoa
);
933 write_b (fnode
* f
, const char *p
, int len
)
936 write_int (f
, p
, len
, btoa
);
941 write_o (fnode
* f
, const char *p
, int len
)
944 write_int (f
, p
, len
, otoa
);
948 write_z (fnode
* f
, const char *p
, int len
)
951 write_int (f
, p
, len
, xtoa
);
956 write_d (fnode
*f
, const char *p
, int len
)
959 write_float (f
, p
, len
);
964 write_e (fnode
*f
, const char *p
, int len
)
967 write_float (f
, p
, len
);
972 write_f (fnode
*f
, const char *p
, int len
)
975 write_float (f
, p
, len
);
980 write_en (fnode
*f
, const char *p
, int len
)
983 write_float (f
, p
, len
);
988 write_es (fnode
*f
, const char *p
, int len
)
991 write_float (f
, p
, len
);
995 /* Take care of the X/TR descriptor. */
1002 p
= write_block (f
->u
.n
);
1006 memset (p
, ' ', f
->u
.n
);
1010 /* List-directed writing. */
1013 /* Write a single character to the output. Returns nonzero if
1014 something goes wrong. */
1021 p
= write_block (1);
1031 /* Write a list-directed logical value. */
1034 write_logical (const char *source
, int length
)
1036 write_char (extract_int (source
, length
) ? 'T' : 'F');
1040 /* Write a list-directed integer value. */
1043 write_integer (const char *source
, int length
)
1050 q
= itoa (extract_int (source
, length
));
1075 digits
= strlen (q
);
1079 p
= write_block (width
) ;
1081 memset(p
,' ', width
- digits
) ;
1082 memcpy (p
+ width
- digits
, q
, digits
);
1086 /* Write a list-directed string. We have to worry about delimiting
1087 the strings if the file has been opened in that mode. */
1090 write_character (const char *source
, int length
)
1095 switch (current_unit
->flags
.delim
)
1097 case DELIM_APOSTROPHE
:
1114 for (i
= 0; i
< length
; i
++)
1119 p
= write_block (length
+ extra
);
1124 memcpy (p
, source
, length
);
1129 for (i
= 0; i
< length
; i
++)
1141 /* Output a real number with default format.
1142 This is 1PG14.7E2 for REAL(4) and 1PG23.15E3 for REAL(8). */
1145 write_real (const char *source
, int length
)
1148 int org_scale
= g
.scale_factor
;
1163 write_float (&f
, source
, length
);
1164 g
.scale_factor
= org_scale
;
1169 write_complex (const char *source
, int len
)
1172 if (write_char ('('))
1174 write_real (source
, len
);
1176 if (write_char (','))
1178 write_real (source
+ len
, len
);
1184 /* Write the separator between items. */
1187 write_separator (void)
1191 p
= write_block (options
.separator_len
);
1195 memcpy (p
, options
.separator
, options
.separator_len
);
1199 /* Write an item with list formatting.
1200 TODO: handle skipping to the next record correctly, particularly
1204 list_formatted_write (bt type
, void *p
, int len
)
1206 static int char_flag
;
1208 if (current_unit
== NULL
)
1219 if (type
!= BT_CHARACTER
|| !char_flag
||
1220 current_unit
->flags
.delim
!= DELIM_NONE
)
1227 write_integer (p
, len
);
1230 write_logical (p
, len
);
1233 write_character (p
, len
);
1236 write_real (p
, len
);
1239 write_complex (p
, len
);
1242 internal_error ("list_formatted_write(): Bad type");
1245 char_flag
= (type
== BT_CHARACTER
);
1249 namelist_write (void)
1251 namelist_info
* t1
, *t2
;
1256 write_character("&",1);
1257 write_character (ioparm
.namelist_name
, ioparm
.namelist_name_len
);
1258 write_character("\n",1);
1270 write_character(t2
->var_name
, strlen(t2
->var_name
));
1271 write_character("=",1);
1278 write_integer (p
, len
);
1281 write_logical (p
, len
);
1284 write_character (p
, t2
->string_length
);
1287 write_real (p
, len
);
1290 write_complex (p
, len
);
1293 internal_error ("Bad type for namelist write");
1295 write_character(",",1);
1299 write_character("\n",1);
1303 write_character("/",1);