2005-06-19 Andreas Krebbel <krebbel1@de.ibm.com>
[official-gcc.git] / libgfortran / io / write.c
blob793031a9375f3f283da295bd166f8e30f30a6f90
1 /* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 Namelist output contibuted by Paul Thomas
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file. (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
19 executable.)
21 Libgfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with Libgfortran; see the file COPYING. If not, write to
28 the Free Software Foundation, 59 Temple Place - Suite 330,
29 Boston, MA 02111-1307, USA. */
31 #include "config.h"
32 #include <string.h>
33 #include <ctype.h>
34 #include <float.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "libgfortran.h"
38 #include "io.h"
41 #define star_fill(p, n) memset(p, '*', n)
44 typedef enum
45 { SIGN_NONE, SIGN_MINUS, SIGN_PLUS }
46 sign_t;
49 static int no_leading_blank = 0 ;
51 void
52 write_a (fnode * f, const char *source, int len)
54 int wlen;
55 char *p;
57 wlen = f->u.string.length < 0 ? len : f->u.string.length;
59 p = write_block (wlen);
60 if (p == NULL)
61 return;
63 if (wlen < len)
64 memcpy (p, source, wlen);
65 else
67 memset (p, ' ', wlen - len);
68 memcpy (p + wlen - len, source, len);
72 static int64_t
73 extract_int (const void *p, int len)
75 int64_t i = 0;
77 if (p == NULL)
78 return i;
80 switch (len)
82 case 1:
83 i = *((const int8_t *) p);
84 break;
85 case 2:
86 i = *((const int16_t *) p);
87 break;
88 case 4:
89 i = *((const int32_t *) p);
90 break;
91 case 8:
92 i = *((const int64_t *) p);
93 break;
94 default:
95 internal_error ("bad integer kind");
98 return i;
101 static double
102 extract_real (const void *p, int len)
104 double i = 0.0;
105 switch (len)
107 case 4:
108 i = *((const float *) p);
109 break;
110 case 8:
111 i = *((const double *) p);
112 break;
113 default:
114 internal_error ("bad real kind");
116 return i;
121 /* Given a flag that indicate if a value is negative or not, return a
122 sign_t that gives the sign that we need to produce. */
124 static sign_t
125 calculate_sign (int negative_flag)
127 sign_t s = SIGN_NONE;
129 if (negative_flag)
130 s = SIGN_MINUS;
131 else
132 switch (g.sign_status)
134 case SIGN_SP:
135 s = SIGN_PLUS;
136 break;
137 case SIGN_SS:
138 s = SIGN_NONE;
139 break;
140 case SIGN_S:
141 s = options.optional_plus ? SIGN_PLUS : SIGN_NONE;
142 break;
145 return s;
149 /* Returns the value of 10**d. */
151 static double
152 calculate_exp (int d)
154 int i;
155 double r = 1.0;
157 for (i = 0; i< (d >= 0 ? d : -d); i++)
158 r *= 10;
160 r = (d >= 0) ? r : 1.0 / r;
162 return r;
166 /* Generate corresponding I/O format for FMT_G output.
167 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
168 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
170 Data Magnitude Equivalent Conversion
171 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
172 m = 0 F(w-n).(d-1), n' '
173 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
174 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
175 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
176 ................ ..........
177 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
178 m >= 10**d-0.5 Ew.d[Ee]
180 notes: for Gw.d , n' ' means 4 blanks
181 for Gw.dEe, n' ' means e+2 blanks */
183 static fnode *
184 calculate_G_format (fnode *f, double value, int *num_blank)
186 int e = f->u.real.e;
187 int d = f->u.real.d;
188 int w = f->u.real.w;
189 fnode *newf;
190 double m, exp_d;
191 int low, high, mid;
192 int ubound, lbound;
194 newf = get_mem (sizeof (fnode));
196 /* Absolute value. */
197 m = (value > 0.0) ? value : -value;
199 /* In case of the two data magnitude ranges,
200 generate E editing, Ew.d[Ee]. */
201 exp_d = calculate_exp (d);
202 if ((m > 0.0 && m < 0.1 - 0.05 / (double) exp_d)
203 || (m >= (double) exp_d - 0.5 ))
205 newf->format = FMT_E;
206 newf->u.real.w = w;
207 newf->u.real.d = d;
208 newf->u.real.e = e;
209 *num_blank = 0;
210 return newf;
213 /* Use binary search to find the data magnitude range. */
214 mid = 0;
215 low = 0;
216 high = d + 1;
217 lbound = 0;
218 ubound = d + 1;
220 while (low <= high)
222 double temp;
223 mid = (low + high) / 2;
225 /* 0.1 * 10**mid - 0.5 * 10**(mid-d-1) */
226 temp = 0.1 * calculate_exp (mid) - 0.5 * calculate_exp (mid - d - 1);
228 if (m < temp)
230 ubound = mid;
231 if (ubound == lbound + 1)
232 break;
233 high = mid - 1;
235 else if (m > temp)
237 lbound = mid;
238 if (ubound == lbound + 1)
240 mid ++;
241 break;
243 low = mid + 1;
245 else
246 break;
249 /* Pad with blanks where the exponent would be. */
250 if (e < 0)
251 *num_blank = 4;
252 else
253 *num_blank = e + 2;
255 /* Generate the F editing. F(w-n).(-(mid-d-1)), n' '. */
256 newf->format = FMT_F;
257 newf->u.real.w = f->u.real.w - *num_blank;
259 /* Special case. */
260 if (m == 0.0)
261 newf->u.real.d = d - 1;
262 else
263 newf->u.real.d = - (mid - d - 1);
265 /* For F editing, the scale factor is ignored. */
266 g.scale_factor = 0;
267 return newf;
271 /* Output a real number according to its format which is FMT_G free. */
273 static void
274 output_float (fnode *f, double value)
276 /* This must be large enough to accurately hold any value. */
277 char buffer[32];
278 char *out;
279 char *digits;
280 int e;
281 char expchar;
282 format_token ft;
283 int w;
284 int d;
285 int edigits;
286 int ndigits;
287 /* Number of digits before the decimal point. */
288 int nbefore;
289 /* Number of zeros after the decimal point. */
290 int nzero;
291 /* Number of digits after the decimal point. */
292 int nafter;
293 /* Number of zeros after the decimal point, whatever the precision. */
294 int nzero_real;
295 int leadzero;
296 int nblanks;
297 int i;
298 sign_t sign;
299 double abslog;
301 ft = f->format;
302 w = f->u.real.w;
303 d = f->u.real.d;
305 nzero_real = -1;
308 /* We should always know the field width and precision. */
309 if (d < 0)
310 internal_error ("Unspecified precision");
312 /* Use sprintf to print the number in the format +D.DDDDe+ddd
313 For an N digit exponent, this gives us (32-6)-N digits after the
314 decimal point, plus another one before the decimal point. */
315 sign = calculate_sign (value < 0.0);
316 if (value < 0)
317 value = -value;
319 /* Printf always prints at least two exponent digits. */
320 if (value == 0)
321 edigits = 2;
322 else
324 abslog = fabs(log10 (value));
325 if (abslog < 100)
326 edigits = 2;
327 else
328 edigits = 1 + (int) log10 (abslog);
331 if (ft == FMT_F || ft == FMT_EN
332 || ((ft == FMT_D || ft == FMT_E) && g.scale_factor != 0))
334 /* Always convert at full precision to avoid double rounding. */
335 ndigits = 27 - edigits;
337 else
339 /* We know the number of digits, so can let printf do the rounding
340 for us. */
341 if (ft == FMT_ES)
342 ndigits = d + 1;
343 else
344 ndigits = d;
345 if (ndigits > 27 - edigits)
346 ndigits = 27 - edigits;
349 sprintf (buffer, "%+-#31.*e", ndigits - 1, value);
351 /* Check the resulting string has punctuation in the correct places. */
352 if (buffer[2] != '.' || buffer[ndigits + 2] != 'e')
353 internal_error ("printf is broken");
355 /* Read the exponent back in. */
356 e = atoi (&buffer[ndigits + 3]) + 1;
358 /* Make sure zero comes out as 0.0e0. */
359 if (value == 0.0)
360 e = 0;
362 /* Normalize the fractional component. */
363 buffer[2] = buffer[1];
364 digits = &buffer[2];
366 /* Figure out where to place the decimal point. */
367 switch (ft)
369 case FMT_F:
370 nbefore = e + g.scale_factor;
371 if (nbefore < 0)
373 nzero = -nbefore;
374 nzero_real = nzero;
375 if (nzero > d)
376 nzero = d;
377 nafter = d - nzero;
378 nbefore = 0;
380 else
382 nzero = 0;
383 nafter = d;
385 expchar = 0;
386 break;
388 case FMT_E:
389 case FMT_D:
390 i = g.scale_factor;
391 if (value != 0.0)
392 e -= i;
393 if (i < 0)
395 nbefore = 0;
396 nzero = -i;
397 nafter = d + i;
399 else if (i > 0)
401 nbefore = i;
402 nzero = 0;
403 nafter = (d - i) + 1;
405 else /* i == 0 */
407 nbefore = 0;
408 nzero = 0;
409 nafter = d;
412 if (ft == FMT_E)
413 expchar = 'E';
414 else
415 expchar = 'D';
416 break;
418 case FMT_EN:
419 /* The exponent must be a multiple of three, with 1-3 digits before
420 the decimal point. */
421 if (value != 0.0)
422 e--;
423 if (e >= 0)
424 nbefore = e % 3;
425 else
427 nbefore = (-e) % 3;
428 if (nbefore != 0)
429 nbefore = 3 - nbefore;
431 e -= nbefore;
432 nbefore++;
433 nzero = 0;
434 nafter = d;
435 expchar = 'E';
436 break;
438 case FMT_ES:
439 if (value != 0.0)
440 e--;
441 nbefore = 1;
442 nzero = 0;
443 nafter = d;
444 expchar = 'E';
445 break;
447 default:
448 /* Should never happen. */
449 internal_error ("Unexpected format token");
452 /* Round the value. */
453 if (nbefore + nafter == 0)
455 ndigits = 0;
456 if (nzero_real == d && digits[0] >= '5')
458 /* We rounded to zero but shouldn't have */
459 nzero--;
460 nafter = 1;
461 digits[0] = '1';
462 ndigits = 1;
465 else if (nbefore + nafter < ndigits)
467 ndigits = nbefore + nafter;
468 i = ndigits;
469 if (digits[i] >= '5')
471 /* Propagate the carry. */
472 for (i--; i >= 0; i--)
474 if (digits[i] != '9')
476 digits[i]++;
477 break;
479 digits[i] = '0';
482 if (i < 0)
484 /* The carry overflowed. Fortunately we have some spare space
485 at the start of the buffer. We may discard some digits, but
486 this is ok because we already know they are zero. */
487 digits--;
488 digits[0] = '1';
489 if (ft == FMT_F)
491 if (nzero > 0)
493 nzero--;
494 nafter++;
496 else
497 nbefore++;
499 else if (ft == FMT_EN)
501 nbefore++;
502 if (nbefore == 4)
504 nbefore = 1;
505 e += 3;
508 else
509 e++;
514 /* Calculate the format of the exponent field. */
515 if (expchar)
517 edigits = 1;
518 for (i = abs (e); i >= 10; i /= 10)
519 edigits++;
521 if (f->u.real.e < 0)
523 /* Width not specified. Must be no more than 3 digits. */
524 if (e > 999 || e < -999)
525 edigits = -1;
526 else
528 edigits = 4;
529 if (e > 99 || e < -99)
530 expchar = ' ';
533 else
535 /* Exponent width specified, check it is wide enough. */
536 if (edigits > f->u.real.e)
537 edigits = -1;
538 else
539 edigits = f->u.real.e + 2;
542 else
543 edigits = 0;
545 /* Pick a field size if none was specified. */
546 if (w <= 0)
547 w = nbefore + nzero + nafter + (sign != SIGN_NONE ? 2 : 1);
549 /* Create the ouput buffer. */
550 out = write_block (w);
551 if (out == NULL)
552 return;
554 /* Zero values always output as positive, even if the value was negative
555 before rounding. */
556 for (i = 0; i < ndigits; i++)
558 if (digits[i] != '0')
559 break;
561 if (i == ndigits)
562 sign = calculate_sign (0);
564 /* Work out how much padding is needed. */
565 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
566 if (sign != SIGN_NONE)
567 nblanks--;
569 /* Check the value fits in the specified field width. */
570 if (nblanks < 0 || edigits == -1)
572 star_fill (out, w);
573 return;
576 /* See if we have space for a zero before the decimal point. */
577 if (nbefore == 0 && nblanks > 0)
579 leadzero = 1;
580 nblanks--;
582 else
583 leadzero = 0;
585 /* Padd to full field width. */
588 if ( ( nblanks > 0 ) && !no_leading_blank )
590 memset (out, ' ', nblanks);
591 out += nblanks;
594 /* Output the initial sign (if any). */
595 if (sign == SIGN_PLUS)
596 *(out++) = '+';
597 else if (sign == SIGN_MINUS)
598 *(out++) = '-';
600 /* Output an optional leading zero. */
601 if (leadzero)
602 *(out++) = '0';
604 /* Output the part before the decimal point, padding with zeros. */
605 if (nbefore > 0)
607 if (nbefore > ndigits)
608 i = ndigits;
609 else
610 i = nbefore;
612 memcpy (out, digits, i);
613 while (i < nbefore)
614 out[i++] = '0';
616 digits += i;
617 ndigits -= i;
618 out += nbefore;
620 /* Output the decimal point. */
621 *(out++) = '.';
623 /* Output leading zeros after the decimal point. */
624 if (nzero > 0)
626 for (i = 0; i < nzero; i++)
627 *(out++) = '0';
630 /* Output digits after the decimal point, padding with zeros. */
631 if (nafter > 0)
633 if (nafter > ndigits)
634 i = ndigits;
635 else
636 i = nafter;
638 memcpy (out, digits, i);
639 while (i < nafter)
640 out[i++] = '0';
642 digits += i;
643 ndigits -= i;
644 out += nafter;
647 /* Output the exponent. */
648 if (expchar)
650 if (expchar != ' ')
652 *(out++) = expchar;
653 edigits--;
655 #if HAVE_SNPRINTF
656 snprintf (buffer, 32, "%+0*d", edigits, e);
657 #else
658 sprintf (buffer, "%+0*d", edigits, e);
659 #endif
660 memcpy (out, buffer, edigits);
663 if ( no_leading_blank )
665 out += edigits;
666 memset( out , ' ' , nblanks );
667 no_leading_blank = 0;
672 void
673 write_l (fnode * f, char *source, int len)
675 char *p;
676 int64_t n;
678 p = write_block (f->u.w);
679 if (p == NULL)
680 return;
682 memset (p, ' ', f->u.w - 1);
683 n = extract_int (source, len);
684 p[f->u.w - 1] = (n) ? 'T' : 'F';
687 /* Output a real number according to its format. */
689 static void
690 write_float (fnode *f, const char *source, int len)
692 double n;
693 int nb =0, res, save_scale_factor;
694 char * p, fin;
695 fnode *f2 = NULL;
697 n = extract_real (source, len);
699 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
701 res = isfinite (n);
702 if (res == 0)
704 nb = f->u.real.w;
705 p = write_block (nb);
706 if (nb < 3)
708 memset (p, '*',nb);
709 return;
712 memset(p, ' ', nb);
713 res = !isnan (n);
714 if (res != 0)
716 if (signbit(n))
717 fin = '-';
718 else
719 fin = '+';
721 if (nb > 7)
722 memcpy(p + nb - 8, "Infinity", 8);
723 else
724 memcpy(p + nb - 3, "Inf", 3);
725 if (nb < 8 && nb > 3)
726 p[nb - 4] = fin;
727 else if (nb > 8)
728 p[nb - 9] = fin;
730 else
731 memcpy(p + nb - 3, "NaN", 3);
732 return;
736 if (f->format != FMT_G)
738 output_float (f, n);
740 else
742 save_scale_factor = g.scale_factor;
743 f2 = calculate_G_format(f, n, &nb);
744 output_float (f2, n);
745 g.scale_factor = save_scale_factor;
746 if (f2 != NULL)
747 free_mem(f2);
749 if (nb > 0)
751 p = write_block (nb);
752 memset (p, ' ', nb);
758 static void
759 write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t))
761 uint32_t ns =0;
762 uint64_t n = 0;
763 int w, m, digits, nzero, nblank;
764 char *p, *q;
766 w = f->u.integer.w;
767 m = f->u.integer.m;
769 n = extract_int (source, len);
771 /* Special case: */
773 if (m == 0 && n == 0)
775 if (w == 0)
776 w = 1;
778 p = write_block (w);
779 if (p == NULL)
780 return;
782 memset (p, ' ', w);
783 goto done;
787 if (len < 8)
789 ns = n;
790 q = conv (ns);
792 else
793 q = conv (n);
795 digits = strlen (q);
797 /* Select a width if none was specified. The idea here is to always
798 print something. */
800 if (w == 0)
801 w = ((digits < m) ? m : digits);
803 p = write_block (w);
804 if (p == NULL)
805 return;
807 nzero = 0;
808 if (digits < m)
809 nzero = m - digits;
811 /* See if things will work. */
813 nblank = w - (nzero + digits);
815 if (nblank < 0)
817 star_fill (p, w);
818 goto done;
822 if (!no_leading_blank)
824 memset (p, ' ', nblank);
825 p += nblank;
826 memset (p, '0', nzero);
827 p += nzero;
828 memcpy (p, q, digits);
830 else
832 memset (p, '0', nzero);
833 p += nzero;
834 memcpy (p, q, digits);
835 p += digits;
836 memset (p, ' ', nblank);
837 no_leading_blank = 0;
840 done:
841 return;
844 static void
845 write_decimal (fnode *f, const char *source, int len, char *(*conv) (int64_t))
847 int64_t n = 0;
848 int w, m, digits, nsign, nzero, nblank;
849 char *p, *q;
850 sign_t sign;
852 w = f->u.integer.w;
853 m = f->u.integer.m;
855 n = extract_int (source, len);
857 /* Special case: */
859 if (m == 0 && n == 0)
861 if (w == 0)
862 w = 1;
864 p = write_block (w);
865 if (p == NULL)
866 return;
868 memset (p, ' ', w);
869 goto done;
872 sign = calculate_sign (n < 0);
873 if (n < 0)
874 n = -n;
876 nsign = sign == SIGN_NONE ? 0 : 1;
877 q = conv (n);
879 digits = strlen (q);
881 /* Select a width if none was specified. The idea here is to always
882 print something. */
884 if (w == 0)
885 w = ((digits < m) ? m : digits) + nsign;
887 p = write_block (w);
888 if (p == NULL)
889 return;
891 nzero = 0;
892 if (digits < m)
893 nzero = m - digits;
895 /* See if things will work. */
897 nblank = w - (nsign + nzero + digits);
899 if (nblank < 0)
901 star_fill (p, w);
902 goto done;
905 memset (p, ' ', nblank);
906 p += nblank;
908 switch (sign)
910 case SIGN_PLUS:
911 *p++ = '+';
912 break;
913 case SIGN_MINUS:
914 *p++ = '-';
915 break;
916 case SIGN_NONE:
917 break;
920 memset (p, '0', nzero);
921 p += nzero;
923 memcpy (p, q, digits);
925 done:
926 return;
930 /* Convert unsigned octal to ascii. */
932 static char *
933 otoa (uint64_t n)
935 char *p;
937 if (n == 0)
939 scratch[0] = '0';
940 scratch[1] = '\0';
941 return scratch;
944 p = scratch + sizeof (SCRATCH_SIZE) - 1;
945 *p-- = '\0';
947 while (n != 0)
949 *p = '0' + (n & 7);
950 p -- ;
951 n >>= 3;
954 return ++p;
958 /* Convert unsigned binary to ascii. */
960 static char *
961 btoa (uint64_t n)
963 char *p;
965 if (n == 0)
967 scratch[0] = '0';
968 scratch[1] = '\0';
969 return scratch;
972 p = scratch + sizeof (SCRATCH_SIZE) - 1;
973 *p-- = '\0';
975 while (n != 0)
977 *p-- = '0' + (n & 1);
978 n >>= 1;
981 return ++p;
985 void
986 write_i (fnode * f, const char *p, int len)
988 write_decimal (f, p, len, (void *) gfc_itoa);
992 void
993 write_b (fnode * f, const char *p, int len)
995 write_int (f, p, len, btoa);
999 void
1000 write_o (fnode * f, const char *p, int len)
1002 write_int (f, p, len, otoa);
1005 void
1006 write_z (fnode * f, const char *p, int len)
1008 write_int (f, p, len, xtoa);
1012 void
1013 write_d (fnode *f, const char *p, int len)
1015 write_float (f, p, len);
1019 void
1020 write_e (fnode *f, const char *p, int len)
1022 write_float (f, p, len);
1026 void
1027 write_f (fnode *f, const char *p, int len)
1029 write_float (f, p, len);
1033 void
1034 write_en (fnode *f, const char *p, int len)
1036 write_float (f, p, len);
1040 void
1041 write_es (fnode *f, const char *p, int len)
1043 write_float (f, p, len);
1047 /* Take care of the X/TR descriptor. */
1049 void
1050 write_x (fnode * f)
1052 char *p;
1054 p = write_block (f->u.n);
1055 if (p == NULL)
1056 return;
1058 memset (p, ' ', f->u.n);
1062 /* List-directed writing. */
1065 /* Write a single character to the output. Returns nonzero if
1066 something goes wrong. */
1068 static int
1069 write_char (char c)
1071 char *p;
1073 p = write_block (1);
1074 if (p == NULL)
1075 return 1;
1077 *p = c;
1079 return 0;
1083 /* Write a list-directed logical value. */
1085 static void
1086 write_logical (const char *source, int length)
1088 write_char (extract_int (source, length) ? 'T' : 'F');
1092 /* Write a list-directed integer value. */
1094 static void
1095 write_integer (const char *source, int length)
1097 char *p;
1098 const char *q;
1099 int digits;
1100 int width;
1102 q = gfc_itoa (extract_int (source, length));
1104 switch (length)
1106 case 1:
1107 width = 4;
1108 break;
1110 case 2:
1111 width = 6;
1112 break;
1114 case 4:
1115 width = 11;
1116 break;
1118 case 8:
1119 width = 20;
1120 break;
1122 default:
1123 width = 0;
1124 break;
1127 digits = strlen (q);
1129 if(width < digits )
1130 width = digits ;
1131 p = write_block (width) ;
1132 if (no_leading_blank)
1134 memcpy (p, q, digits);
1135 memset(p + digits ,' ', width - digits) ;
1137 else
1139 memset(p ,' ', width - digits) ;
1140 memcpy (p + width - digits, q, digits);
1145 /* Write a list-directed string. We have to worry about delimiting
1146 the strings if the file has been opened in that mode. */
1148 static void
1149 write_character (const char *source, int length)
1151 int i, extra;
1152 char *p, d;
1154 switch (current_unit->flags.delim)
1156 case DELIM_APOSTROPHE:
1157 d = '\'';
1158 break;
1159 case DELIM_QUOTE:
1160 d = '"';
1161 break;
1162 default:
1163 d = ' ';
1164 break;
1167 if (d == ' ')
1168 extra = 0;
1169 else
1171 extra = 2;
1173 for (i = 0; i < length; i++)
1174 if (source[i] == d)
1175 extra++;
1178 p = write_block (length + extra);
1179 if (p == NULL)
1180 return;
1182 if (d == ' ')
1183 memcpy (p, source, length);
1184 else
1186 *p++ = d;
1188 for (i = 0; i < length; i++)
1190 *p++ = source[i];
1191 if (source[i] == d)
1192 *p++ = d;
1195 *p = d;
1200 /* Output a real number with default format.
1201 This is 1PG14.7E2 for REAL(4) and 1PG23.15E3 for REAL(8). */
1203 static void
1204 write_real (const char *source, int length)
1206 fnode f ;
1207 int org_scale = g.scale_factor;
1208 f.format = FMT_G;
1209 g.scale_factor = 1;
1210 if (length < 8)
1212 f.u.real.w = 14;
1213 f.u.real.d = 7;
1214 f.u.real.e = 2;
1216 else
1218 f.u.real.w = 23;
1219 f.u.real.d = 15;
1220 f.u.real.e = 3;
1222 write_float (&f, source , length);
1223 g.scale_factor = org_scale;
1227 static void
1228 write_complex (const char *source, int len)
1230 if (write_char ('('))
1231 return;
1232 write_real (source, len);
1234 if (write_char (','))
1235 return;
1236 write_real (source + len, len);
1238 write_char (')');
1242 /* Write the separator between items. */
1244 static void
1245 write_separator (void)
1247 char *p;
1249 p = write_block (options.separator_len);
1250 if (p == NULL)
1251 return;
1253 memcpy (p, options.separator, options.separator_len);
1257 /* Write an item with list formatting.
1258 TODO: handle skipping to the next record correctly, particularly
1259 with strings. */
1261 void
1262 list_formatted_write (bt type, void *p, int len)
1264 static int char_flag;
1266 if (current_unit == NULL)
1267 return;
1269 if (g.first_item)
1271 g.first_item = 0;
1272 char_flag = 0;
1273 write_char (' ');
1275 else
1277 if (type != BT_CHARACTER || !char_flag ||
1278 current_unit->flags.delim != DELIM_NONE)
1279 write_separator ();
1282 switch (type)
1284 case BT_INTEGER:
1285 write_integer (p, len);
1286 break;
1287 case BT_LOGICAL:
1288 write_logical (p, len);
1289 break;
1290 case BT_CHARACTER:
1291 write_character (p, len);
1292 break;
1293 case BT_REAL:
1294 write_real (p, len);
1295 break;
1296 case BT_COMPLEX:
1297 write_complex (p, len);
1298 break;
1299 default:
1300 internal_error ("list_formatted_write(): Bad type");
1303 char_flag = (type == BT_CHARACTER);
1306 /* NAMELIST OUTPUT
1308 nml_write_obj writes a namelist object to the output stream. It is called
1309 recursively for derived type components:
1310 obj = is the namelist_info for the current object.
1311 offset = the offset relative to the address held by the object for
1312 derived type arrays.
1313 base = is the namelist_info of the derived type, when obj is a
1314 component.
1315 base_name = the full name for a derived type, including qualifiers
1316 if any.
1317 The returned value is a pointer to the object beyond the last one
1318 accessed, including nested derived types. Notice that the namelist is
1319 a linear linked list of objects, including derived types and their
1320 components. A tree, of sorts, is implied by the compound names of
1321 the derived type components and this is how this function recurses through
1322 the list. */
1324 /* A generous estimate of the number of characters needed to print
1325 repeat counts and indices, including commas, asterices and brackets. */
1327 #define NML_DIGITS 20
1329 /* Stores the delimiter to be used for character objects. */
1331 static const char * nml_delim;
1333 static namelist_info *
1334 nml_write_obj (namelist_info * obj, index_type offset,
1335 namelist_info * base, char * base_name)
1337 int rep_ctr;
1338 int num;
1339 int nml_carry;
1340 index_type len;
1341 index_type obj_size;
1342 index_type nelem;
1343 index_type dim_i;
1344 index_type clen;
1345 index_type elem_ctr;
1346 index_type obj_name_len;
1347 void * p ;
1348 char cup;
1349 char * obj_name;
1350 char * ext_name;
1351 char rep_buff[NML_DIGITS];
1352 namelist_info * cmp;
1353 namelist_info * retval = obj->next;
1355 /* Write namelist variable names in upper case. If a derived type,
1356 nothing is output. If a component, base and base_name are set. */
1358 if (obj->type != GFC_DTYPE_DERIVED)
1360 write_character ("\n ", 2);
1361 len = 0;
1362 if (base)
1364 len =strlen (base->var_name);
1365 for (dim_i = 0; dim_i < (index_type) strlen (base_name); dim_i++)
1367 cup = toupper (base_name[dim_i]);
1368 write_character (&cup, 1);
1371 for (dim_i =len; dim_i < (index_type) strlen (obj->var_name); dim_i++)
1373 cup = toupper (obj->var_name[dim_i]);
1374 write_character (&cup, 1);
1376 write_character ("=", 1);
1379 /* Counts the number of data output on a line, including names. */
1381 num = 1;
1383 len = obj->len;
1384 obj_size = len;
1385 if (obj->type == GFC_DTYPE_COMPLEX)
1386 obj_size = 2*len;
1387 if (obj->type == GFC_DTYPE_CHARACTER)
1388 obj_size = obj->string_length;
1389 if (obj->var_rank)
1390 obj_size = obj->size;
1392 /* Set the index vector and count the number of elements. */
1394 nelem = 1;
1395 for (dim_i=0; dim_i < obj->var_rank; dim_i++)
1397 obj->ls[dim_i].idx = obj->dim[dim_i].lbound;
1398 nelem = nelem * (obj->dim[dim_i].ubound + 1 - obj->dim[dim_i].lbound);
1401 /* Main loop to output the data held in the object. */
1403 rep_ctr = 1;
1404 for (elem_ctr = 0; elem_ctr < nelem; elem_ctr++)
1407 /* Build the pointer to the data value. The offset is passed by
1408 recursive calls to this function for arrays of derived types.
1409 Is NULL otherwise. */
1411 p = (void *)(obj->mem_pos + elem_ctr * obj_size);
1412 p += offset;
1414 /* Check for repeat counts of intrinsic types. */
1416 if ((elem_ctr < (nelem - 1)) &&
1417 (obj->type != GFC_DTYPE_DERIVED) &&
1418 !memcmp (p, (void*)(p + obj_size ), obj_size ))
1420 rep_ctr++;
1423 /* Execute a repeated output. Note the flag no_leading_blank that
1424 is used in the functions used to output the intrinsic types. */
1426 else
1428 if (rep_ctr > 1)
1430 st_sprintf(rep_buff, " %d*", rep_ctr);
1431 write_character (rep_buff, strlen (rep_buff));
1432 no_leading_blank = 1;
1434 num++;
1436 /* Output the data, if an intrinsic type, or recurse into this
1437 routine to treat derived types. */
1439 switch (obj->type)
1442 case GFC_DTYPE_INTEGER:
1443 write_integer (p, len);
1444 break;
1446 case GFC_DTYPE_LOGICAL:
1447 write_logical (p, len);
1448 break;
1450 case GFC_DTYPE_CHARACTER:
1451 if (nml_delim)
1452 write_character (nml_delim, 1);
1453 write_character (p, obj->string_length);
1454 if (nml_delim)
1455 write_character (nml_delim, 1);
1456 break;
1458 case GFC_DTYPE_REAL:
1459 write_real (p, len);
1460 break;
1462 case GFC_DTYPE_COMPLEX:
1463 no_leading_blank = 0;
1464 num++;
1465 write_complex (p, len);
1466 break;
1468 case GFC_DTYPE_DERIVED:
1470 /* To treat a derived type, we need to build two strings:
1471 ext_name = the name, including qualifiers that prepends
1472 component names in the output - passed to
1473 nml_write_obj.
1474 obj_name = the derived type name with no qualifiers but %
1475 appended. This is used to identify the
1476 components. */
1478 /* First ext_name => get length of all possible components */
1480 ext_name = (char*)get_mem ( (base_name ? strlen (base_name) : 0)
1481 + (base ? strlen (base->var_name) : 0)
1482 + strlen (obj->var_name)
1483 + obj->var_rank * NML_DIGITS
1484 + 1);
1486 strcpy(ext_name, base_name ? base_name : "");
1487 clen = base ? strlen (base->var_name) : 0;
1488 strcat (ext_name, obj->var_name + clen);
1490 /* Append the qualifier. */
1492 for (dim_i = 0; dim_i < obj->var_rank; dim_i++)
1494 strcat (ext_name, dim_i ? "" : "(");
1495 clen = strlen (ext_name);
1496 st_sprintf (ext_name + clen, "%d", (int) obj->ls[dim_i].idx);
1497 strcat (ext_name, (dim_i == obj->var_rank - 1) ? ")" : ",");
1500 /* Now obj_name. */
1502 obj_name_len = strlen (obj->var_name) + 1;
1503 obj_name = get_mem (obj_name_len+1);
1504 strcpy (obj_name, obj->var_name);
1505 strcat (obj_name, "%");
1507 /* Now loop over the components. Update the component pointer
1508 with the return value from nml_write_obj => this loop jumps
1509 past nested derived types. */
1511 for (cmp = obj->next;
1512 cmp && !strncmp (cmp->var_name, obj_name, obj_name_len);
1513 cmp = retval)
1515 retval = nml_write_obj (cmp, (index_type)(p - obj->mem_pos),
1516 obj, ext_name);
1519 free_mem (obj_name);
1520 free_mem (ext_name);
1521 goto obj_loop;
1523 default:
1524 internal_error ("Bad type for namelist write");
1527 /* Reset the leading blank suppression, write a comma and, if 5
1528 values have been output, write a newline and advance to column
1529 2. Reset the repeat counter. */
1531 no_leading_blank = 0;
1532 write_character (",", 1);
1533 if (num > 5)
1535 num = 0;
1536 write_character ("\n ", 2);
1538 rep_ctr = 1;
1541 /* Cycle through and increment the index vector. */
1543 obj_loop:
1545 nml_carry = 1;
1546 for (dim_i = 0; nml_carry && (dim_i < obj->var_rank); dim_i++)
1548 obj->ls[dim_i].idx += nml_carry ;
1549 nml_carry = 0;
1550 if (obj->ls[dim_i].idx > (ssize_t)obj->dim[dim_i].ubound)
1552 obj->ls[dim_i].idx = obj->dim[dim_i].lbound;
1553 nml_carry = 1;
1558 /* Return a pointer beyond the furthest object accessed. */
1560 return retval;
1563 /* This is the entry function for namelist writes. It outputs the name
1564 of the namelist and iterates through the namelist by calls to
1565 nml_write_obj. The call below has dummys in the arguments used in
1566 the treatment of derived types. */
1568 void
1569 namelist_write (void)
1571 namelist_info * t1, *t2, *dummy = NULL;
1572 index_type i;
1573 index_type dummy_offset = 0;
1574 char c;
1575 char * dummy_name = NULL;
1576 unit_delim tmp_delim;
1578 /* Set the delimiter for namelist output. */
1580 tmp_delim = current_unit->flags.delim;
1581 current_unit->flags.delim = DELIM_NONE;
1582 switch (tmp_delim)
1584 case (DELIM_QUOTE):
1585 nml_delim = "\"";
1586 break;
1588 case (DELIM_APOSTROPHE):
1589 nml_delim = "'";
1590 break;
1592 default:
1593 nml_delim = NULL;
1596 write_character ("&",1);
1598 /* Write namelist name in upper case - f95 std. */
1600 for (i = 0 ;i < ioparm.namelist_name_len ;i++ )
1602 c = toupper (ioparm.namelist_name[i]);
1603 write_character (&c ,1);
1606 if (ionml != NULL)
1608 t1 = ionml;
1609 while (t1 != NULL)
1611 t2 = t1;
1612 t1 = nml_write_obj (t2, dummy_offset, dummy, dummy_name);
1615 write_character (" /\n", 4);
1617 /* Recover the original delimiter. */
1619 current_unit->flags.delim = tmp_delim;
1622 #undef NML_DIGITS