1 /* Copyright (C) 2002, 2003, 2004, 2005 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 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file. (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
20 Libgfortran is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with Libgfortran; see the file COPYING. If not, write to
27 the Free Software Foundation, 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. */
35 #include "libgfortran.h"
39 #define star_fill(p, n) memset(p, '*', n)
43 { SIGN_NONE
, SIGN_MINUS
, SIGN_PLUS
}
48 write_a (fnode
* f
, const char *source
, int len
)
53 wlen
= f
->u
.string
.length
< 0 ? len
: f
->u
.string
.length
;
55 p
= write_block (wlen
);
60 memcpy (p
, source
, wlen
);
63 memset (p
, ' ', wlen
- len
);
64 memcpy (p
+ wlen
- len
, source
, len
);
69 extract_int (const void *p
, int len
)
79 i
= *((const int8_t *) p
);
82 i
= *((const int16_t *) p
);
85 i
= *((const int32_t *) p
);
88 i
= *((const int64_t *) p
);
91 internal_error ("bad integer kind");
98 extract_real (const void *p
, int len
)
104 i
= *((const float *) p
);
107 i
= *((const double *) p
);
110 internal_error ("bad real kind");
117 /* Given a flag that indicate if a value is negative or not, return a
118 sign_t that gives the sign that we need to produce. */
121 calculate_sign (int negative_flag
)
123 sign_t s
= SIGN_NONE
;
128 switch (g
.sign_status
)
137 s
= options
.optional_plus
? SIGN_PLUS
: SIGN_NONE
;
145 /* Returns the value of 10**d. */
148 calculate_exp (int d
)
153 for (i
= 0; i
< (d
>= 0 ? d
: -d
); i
++)
156 r
= (d
>= 0) ? r
: 1.0 / r
;
162 /* Generate corresponding I/O format for FMT_G output.
163 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
164 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
166 Data Magnitude Equivalent Conversion
167 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
168 m = 0 F(w-n).(d-1), n' '
169 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
170 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
171 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
172 ................ ..........
173 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
174 m >= 10**d-0.5 Ew.d[Ee]
176 notes: for Gw.d , n' ' means 4 blanks
177 for Gw.dEe, n' ' means e+2 blanks */
180 calculate_G_format (fnode
*f
, double value
, int len
, int *num_blank
)
190 newf
= get_mem (sizeof (fnode
));
192 /* Absolute value. */
193 m
= (value
> 0.0) ? value
: -value
;
195 /* In case of the two data magnitude ranges,
196 generate E editing, Ew.d[Ee]. */
197 exp_d
= calculate_exp (d
);
198 if ((m
> 0.0 && m
< 0.1 - 0.05 / (double) exp_d
)
199 || (m
>= (double) exp_d
- 0.5 ))
201 newf
->format
= FMT_E
;
209 /* Use binary search to find the data magnitude range. */
219 mid
= (low
+ high
) / 2;
221 /* 0.1 * 10**mid - 0.5 * 10**(mid-d-1) */
222 temp
= 0.1 * calculate_exp (mid
) - 0.5 * calculate_exp (mid
- d
- 1);
227 if (ubound
== lbound
+ 1)
234 if (ubound
== lbound
+ 1)
245 /* Pad with blanks where the exponent would be. */
251 /* Generate the F editing. F(w-n).(-(mid-d-1)), n' '. */
252 newf
->format
= FMT_F
;
253 newf
->u
.real
.w
= f
->u
.real
.w
- *num_blank
;
257 newf
->u
.real
.d
= d
- 1;
259 newf
->u
.real
.d
= - (mid
- d
- 1);
261 /* For F editing, the scale factor is ignored. */
267 /* Output a real number according to its format which is FMT_G free. */
270 output_float (fnode
*f
, double value
, int len
)
272 /* This must be large enough to accurately hold any value. */
283 /* Number of digits before the decimal point. */
285 /* Number of zeros after the decimal point. */
287 /* Number of digits after the decimal point. */
289 /* Number of zeros after the decimal point, whatever the precision. */
303 /* We should always know the field width and precision. */
305 internal_error ("Unspecified precision");
307 /* Use sprintf to print the number in the format +D.DDDDe+ddd
308 For an N digit exponent, this gives us (32-6)-N digits after the
309 decimal point, plus another one before the decimal point. */
310 sign
= calculate_sign (value
< 0.0);
314 /* Printf always prints at least two exponent digits. */
319 edigits
= 1 + (int) log10 (fabs(log10 (value
)));
324 if (ft
== FMT_F
|| ft
== FMT_EN
325 || ((ft
== FMT_D
|| ft
== FMT_E
) && g
.scale_factor
!= 0))
327 /* Always convert at full precision to avoid double rounding. */
328 ndigits
= 27 - edigits
;
332 /* We know the number of digits, so can let printf do the rounding
338 if (ndigits
> 27 - edigits
)
339 ndigits
= 27 - edigits
;
342 sprintf (buffer
, "%+-#31.*e", ndigits
- 1, value
);
344 /* Check the resulting string has punctuation in the correct places. */
345 if (buffer
[2] != '.' || buffer
[ndigits
+ 2] != 'e')
346 internal_error ("printf is broken");
348 /* Read the exponent back in. */
349 e
= atoi (&buffer
[ndigits
+ 3]) + 1;
351 /* Make sure zero comes out as 0.0e0. */
355 /* Normalize the fractional component. */
356 buffer
[2] = buffer
[1];
359 /* Figure out where to place the decimal point. */
363 nbefore
= e
+ g
.scale_factor
;
396 nafter
= (d
- i
) + 1;
412 /* The exponent must be a multiple of three, with 1-3 digits before
413 the decimal point. */
422 nbefore
= 3 - nbefore
;
441 /* Should never happen. */
442 internal_error ("Unexpected format token");
445 /* Round the value. */
446 if (nbefore
+ nafter
== 0)
449 if (nzero_real
== d
&& digits
[0] >= '5')
451 /* We rounded to zero but shouldn't have */
458 else if (nbefore
+ nafter
< ndigits
)
460 ndigits
= nbefore
+ nafter
;
462 if (digits
[i
] >= '5')
464 /* Propagate the carry. */
465 for (i
--; i
>= 0; i
--)
467 if (digits
[i
] != '9')
477 /* The carry overflowed. Fortunately we have some spare space
478 at the start of the buffer. We may discard some digits, but
479 this is ok because we already know they are zero. */
492 else if (ft
== FMT_EN
)
507 /* Calculate the format of the exponent field. */
511 for (i
= abs (e
); i
>= 10; i
/= 10)
516 /* Width not specified. Must be no more than 3 digits. */
517 if (e
> 999 || e
< -999)
522 if (e
> 99 || e
< -99)
528 /* Exponent width specified, check it is wide enough. */
529 if (edigits
> f
->u
.real
.e
)
532 edigits
= f
->u
.real
.e
+ 2;
538 /* Pick a field size if none was specified. */
540 w
= nbefore
+ nzero
+ nafter
+ (sign
!= SIGN_NONE
? 2 : 1);
542 /* Create the ouput buffer. */
543 out
= write_block (w
);
547 /* Zero values always output as positive, even if the value was negative
549 for (i
= 0; i
< ndigits
; i
++)
551 if (digits
[i
] != '0')
555 sign
= calculate_sign (0);
557 /* Work out how much padding is needed. */
558 nblanks
= w
- (nbefore
+ nzero
+ nafter
+ edigits
+ 1);
559 if (sign
!= SIGN_NONE
)
562 /* Check the value fits in the specified field width. */
563 if (nblanks
< 0 || edigits
== -1)
569 /* See if we have space for a zero before the decimal point. */
570 if (nbefore
== 0 && nblanks
> 0)
578 /* Padd to full field width. */
581 memset (out
, ' ', nblanks
);
585 /* Output the initial sign (if any). */
586 if (sign
== SIGN_PLUS
)
588 else if (sign
== SIGN_MINUS
)
591 /* Output an optional leading zero. */
595 /* Output the part before the decimal point, padding with zeros. */
598 if (nbefore
> ndigits
)
603 memcpy (out
, digits
, i
);
611 /* Output the decimal point. */
614 /* Output leading zeros after the decimal point. */
617 for (i
= 0; i
< nzero
; i
++)
621 /* Output digits after the decimal point, padding with zeros. */
624 if (nafter
> ndigits
)
629 memcpy (out
, digits
, i
);
638 /* Output the exponent. */
647 snprintf (buffer
, 32, "%+0*d", edigits
, e
);
649 sprintf (buffer
, "%+0*d", edigits
, e
);
651 memcpy (out
, buffer
, edigits
);
657 write_l (fnode
* f
, char *source
, int len
)
662 p
= write_block (f
->u
.w
);
666 memset (p
, ' ', f
->u
.w
- 1);
667 n
= extract_int (source
, len
);
668 p
[f
->u
.w
- 1] = (n
) ? 'T' : 'F';
671 /* Output a real number according to its format. */
674 write_float (fnode
*f
, const char *source
, int len
)
681 n
= extract_real (source
, len
);
683 if (f
->format
!= FMT_B
&& f
->format
!= FMT_O
&& f
->format
!= FMT_Z
)
689 p
= write_block (nb
);
706 memcpy(p
+ nb
- 8, "Infinity", 8);
708 memcpy(p
+ nb
- 3, "Inf", 3);
709 if (nb
< 8 && nb
> 3)
715 memcpy(p
+ nb
- 3, "NaN", 3);
720 if (f
->format
!= FMT_G
)
722 output_float (f
, n
, len
);
726 f2
= calculate_G_format(f
, n
, len
, &nb
);
727 output_float (f2
, n
, len
);
733 p
= write_block (nb
);
741 write_int (fnode
*f
, const char *source
, int len
, char *(*conv
) (uint64_t))
745 int w
, m
, digits
, nzero
, nblank
;
751 n
= extract_int (source
, len
);
755 if (m
== 0 && n
== 0)
779 /* Select a width if none was specified. The idea here is to always
783 w
= ((digits
< m
) ? m
: digits
);
793 /* See if things will work. */
795 nblank
= w
- (nzero
+ digits
);
803 memset (p
, ' ', nblank
);
806 memset (p
, '0', nzero
);
809 memcpy (p
, q
, digits
);
816 write_decimal (fnode
*f
, const char *source
, int len
, char *(*conv
) (int64_t))
819 int w
, m
, digits
, nsign
, nzero
, nblank
;
826 n
= extract_int (source
, len
);
830 if (m
== 0 && n
== 0)
843 sign
= calculate_sign (n
< 0);
847 nsign
= sign
== SIGN_NONE
? 0 : 1;
852 /* Select a width if none was specified. The idea here is to always
856 w
= ((digits
< m
) ? m
: digits
) + nsign
;
866 /* See if things will work. */
868 nblank
= w
- (nsign
+ nzero
+ digits
);
876 memset (p
, ' ', nblank
);
891 memset (p
, '0', nzero
);
894 memcpy (p
, q
, digits
);
901 /* Convert unsigned octal to ascii. */
915 p
= scratch
+ sizeof (SCRATCH_SIZE
) - 1;
929 /* Convert unsigned binary to ascii. */
943 p
= scratch
+ sizeof (SCRATCH_SIZE
) - 1;
948 *p
-- = '0' + (n
& 1);
957 write_i (fnode
* f
, const char *p
, int len
)
959 write_decimal (f
, p
, len
, (void *) gfc_itoa
);
964 write_b (fnode
* f
, const char *p
, int len
)
966 write_int (f
, p
, len
, btoa
);
971 write_o (fnode
* f
, const char *p
, int len
)
973 write_int (f
, p
, len
, otoa
);
977 write_z (fnode
* f
, const char *p
, int len
)
979 write_int (f
, p
, len
, xtoa
);
984 write_d (fnode
*f
, const char *p
, int len
)
986 write_float (f
, p
, len
);
991 write_e (fnode
*f
, const char *p
, int len
)
993 write_float (f
, p
, len
);
998 write_f (fnode
*f
, const char *p
, int len
)
1000 write_float (f
, p
, len
);
1005 write_en (fnode
*f
, const char *p
, int len
)
1007 write_float (f
, p
, len
);
1012 write_es (fnode
*f
, const char *p
, int len
)
1014 write_float (f
, p
, len
);
1018 /* Take care of the X/TR descriptor. */
1025 p
= write_block (f
->u
.n
);
1029 memset (p
, ' ', f
->u
.n
);
1033 /* List-directed writing. */
1036 /* Write a single character to the output. Returns nonzero if
1037 something goes wrong. */
1044 p
= write_block (1);
1054 /* Write a list-directed logical value. */
1057 write_logical (const char *source
, int length
)
1059 write_char (extract_int (source
, length
) ? 'T' : 'F');
1063 /* Write a list-directed integer value. */
1066 write_integer (const char *source
, int length
)
1073 q
= gfc_itoa (extract_int (source
, length
));
1098 digits
= strlen (q
);
1102 p
= write_block (width
) ;
1104 memset(p
,' ', width
- digits
) ;
1105 memcpy (p
+ width
- digits
, q
, digits
);
1109 /* Write a list-directed string. We have to worry about delimiting
1110 the strings if the file has been opened in that mode. */
1113 write_character (const char *source
, int length
)
1118 switch (current_unit
->flags
.delim
)
1120 case DELIM_APOSTROPHE
:
1137 for (i
= 0; i
< length
; i
++)
1142 p
= write_block (length
+ extra
);
1147 memcpy (p
, source
, length
);
1152 for (i
= 0; i
< length
; i
++)
1164 /* Output a real number with default format.
1165 This is 1PG14.7E2 for REAL(4) and 1PG23.15E3 for REAL(8). */
1168 write_real (const char *source
, int length
)
1171 int org_scale
= g
.scale_factor
;
1186 write_float (&f
, source
, length
);
1187 g
.scale_factor
= org_scale
;
1192 write_complex (const char *source
, int len
)
1194 if (write_char ('('))
1196 write_real (source
, len
);
1198 if (write_char (','))
1200 write_real (source
+ len
, len
);
1206 /* Write the separator between items. */
1209 write_separator (void)
1213 p
= write_block (options
.separator_len
);
1217 memcpy (p
, options
.separator
, options
.separator_len
);
1221 /* Write an item with list formatting.
1222 TODO: handle skipping to the next record correctly, particularly
1226 list_formatted_write (bt type
, void *p
, int len
)
1228 static int char_flag
;
1230 if (current_unit
== NULL
)
1241 if (type
!= BT_CHARACTER
|| !char_flag
||
1242 current_unit
->flags
.delim
!= DELIM_NONE
)
1249 write_integer (p
, len
);
1252 write_logical (p
, len
);
1255 write_character (p
, len
);
1258 write_real (p
, len
);
1261 write_complex (p
, len
);
1264 internal_error ("list_formatted_write(): Bad type");
1267 char_flag
= (type
== BT_CHARACTER
);
1271 namelist_write (void)
1273 namelist_info
* t1
, *t2
;
1278 write_character("&",1);
1279 write_character (ioparm
.namelist_name
, ioparm
.namelist_name_len
);
1280 write_character("\n",1);
1292 write_character(t2
->var_name
, strlen(t2
->var_name
));
1293 write_character("=",1);
1300 write_integer (p
, len
);
1303 write_logical (p
, len
);
1306 write_character (p
, t2
->string_length
);
1309 write_real (p
, len
);
1312 write_complex (p
, len
);
1315 internal_error ("Bad type for namelist write");
1317 write_character(",",1);
1321 write_character("\n",1);
1325 write_character("/",1);