re PR fortran/36420 (Fortran 2008: g0 edit descriptor)
[gcc.git] / libgfortran / io / write.c
1 /* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
2 Free Software Foundation, Inc.
3 Contributed by Andy Vaught
4 Namelist output contributed by Paul Thomas
5 F2003 I/O support contributed by Jerry DeLisle
6
7 This file is part of the GNU Fortran 95 runtime library (libgfortran).
8
9 Libgfortran is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13
14 In addition to the permissions in the GNU General Public License, the
15 Free Software Foundation gives you unlimited permission to link the
16 compiled version of this file into combinations with other programs,
17 and to distribute those combinations without any restriction coming
18 from the use of this file. (The General Public License restrictions
19 do apply in other respects; for example, they cover modification of
20 the file, and distribution when not linked into a combine
21 executable.)
22
23 Libgfortran is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with Libgfortran; see the file COPYING. If not, write to
30 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
31 Boston, MA 02110-1301, USA. */
32
33 #include "io.h"
34 #include <assert.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39 #define star_fill(p, n) memset(p, '*', n)
40
41 #include "write_float.def"
42
43 void
44 write_a (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
45 {
46 int wlen;
47 char *p;
48
49 wlen = f->u.string.length < 0
50 || (f->format == FMT_G && f->u.string.length == 0)
51 ? len : f->u.string.length;
52
53 #ifdef HAVE_CRLF
54 /* If this is formatted STREAM IO convert any embedded line feed characters
55 to CR_LF on systems that use that sequence for newlines. See F2003
56 Standard sections 10.6.3 and 9.9 for further information. */
57 if (is_stream_io (dtp))
58 {
59 const char crlf[] = "\r\n";
60 int i, q, bytes;
61 q = bytes = 0;
62
63 /* Write out any padding if needed. */
64 if (len < wlen)
65 {
66 p = write_block (dtp, wlen - len);
67 if (p == NULL)
68 return;
69 memset (p, ' ', wlen - len);
70 }
71
72 /* Scan the source string looking for '\n' and convert it if found. */
73 for (i = 0; i < wlen; i++)
74 {
75 if (source[i] == '\n')
76 {
77 /* Write out the previously scanned characters in the string. */
78 if (bytes > 0)
79 {
80 p = write_block (dtp, bytes);
81 if (p == NULL)
82 return;
83 memcpy (p, &source[q], bytes);
84 q += bytes;
85 bytes = 0;
86 }
87
88 /* Write out the CR_LF sequence. */
89 q++;
90 p = write_block (dtp, 2);
91 if (p == NULL)
92 return;
93 memcpy (p, crlf, 2);
94 }
95 else
96 bytes++;
97 }
98
99 /* Write out any remaining bytes if no LF was found. */
100 if (bytes > 0)
101 {
102 p = write_block (dtp, bytes);
103 if (p == NULL)
104 return;
105 memcpy (p, &source[q], bytes);
106 }
107 }
108 else
109 {
110 #endif
111 p = write_block (dtp, wlen);
112 if (p == NULL)
113 return;
114
115 if (wlen < len)
116 memcpy (p, source, wlen);
117 else
118 {
119 memset (p, ' ', wlen - len);
120 memcpy (p + wlen - len, source, len);
121 }
122 #ifdef HAVE_CRLF
123 }
124 #endif
125 }
126
127 static GFC_INTEGER_LARGEST
128 extract_int (const void *p, int len)
129 {
130 GFC_INTEGER_LARGEST i = 0;
131
132 if (p == NULL)
133 return i;
134
135 switch (len)
136 {
137 case 1:
138 {
139 GFC_INTEGER_1 tmp;
140 memcpy ((void *) &tmp, p, len);
141 i = tmp;
142 }
143 break;
144 case 2:
145 {
146 GFC_INTEGER_2 tmp;
147 memcpy ((void *) &tmp, p, len);
148 i = tmp;
149 }
150 break;
151 case 4:
152 {
153 GFC_INTEGER_4 tmp;
154 memcpy ((void *) &tmp, p, len);
155 i = tmp;
156 }
157 break;
158 case 8:
159 {
160 GFC_INTEGER_8 tmp;
161 memcpy ((void *) &tmp, p, len);
162 i = tmp;
163 }
164 break;
165 #ifdef HAVE_GFC_INTEGER_16
166 case 16:
167 {
168 GFC_INTEGER_16 tmp;
169 memcpy ((void *) &tmp, p, len);
170 i = tmp;
171 }
172 break;
173 #endif
174 default:
175 internal_error (NULL, "bad integer kind");
176 }
177
178 return i;
179 }
180
181 static GFC_UINTEGER_LARGEST
182 extract_uint (const void *p, int len)
183 {
184 GFC_UINTEGER_LARGEST i = 0;
185
186 if (p == NULL)
187 return i;
188
189 switch (len)
190 {
191 case 1:
192 {
193 GFC_INTEGER_1 tmp;
194 memcpy ((void *) &tmp, p, len);
195 i = (GFC_UINTEGER_1) tmp;
196 }
197 break;
198 case 2:
199 {
200 GFC_INTEGER_2 tmp;
201 memcpy ((void *) &tmp, p, len);
202 i = (GFC_UINTEGER_2) tmp;
203 }
204 break;
205 case 4:
206 {
207 GFC_INTEGER_4 tmp;
208 memcpy ((void *) &tmp, p, len);
209 i = (GFC_UINTEGER_4) tmp;
210 }
211 break;
212 case 8:
213 {
214 GFC_INTEGER_8 tmp;
215 memcpy ((void *) &tmp, p, len);
216 i = (GFC_UINTEGER_8) tmp;
217 }
218 break;
219 #ifdef HAVE_GFC_INTEGER_16
220 case 16:
221 {
222 GFC_INTEGER_16 tmp;
223 memcpy ((void *) &tmp, p, len);
224 i = (GFC_UINTEGER_16) tmp;
225 }
226 break;
227 #endif
228 default:
229 internal_error (NULL, "bad integer kind");
230 }
231
232 return i;
233 }
234
235
236 void
237 write_l (st_parameter_dt *dtp, const fnode *f, char *source, int len)
238 {
239 char *p;
240 int wlen;
241 GFC_INTEGER_LARGEST n;
242
243 wlen = (f->format == FMT_G && f->u.w == 0) ? 1 : f->u.w;
244
245 p = write_block (dtp, wlen);
246 if (p == NULL)
247 return;
248
249 memset (p, ' ', wlen - 1);
250 n = extract_int (source, len);
251 p[wlen - 1] = (n) ? 'T' : 'F';
252 }
253
254
255 static void
256 write_int (st_parameter_dt *dtp, const fnode *f, const char *source, int len,
257 const char *(*conv) (GFC_UINTEGER_LARGEST, char *, size_t))
258 {
259 GFC_UINTEGER_LARGEST n = 0;
260 int w, m, digits, nzero, nblank;
261 char *p;
262 const char *q;
263 char itoa_buf[GFC_BTOA_BUF_SIZE];
264
265 w = f->u.integer.w;
266 m = f->u.integer.m;
267
268 n = extract_uint (source, len);
269
270 /* Special case: */
271
272 if (m == 0 && n == 0)
273 {
274 if (w == 0)
275 w = 1;
276
277 p = write_block (dtp, w);
278 if (p == NULL)
279 return;
280
281 memset (p, ' ', w);
282 goto done;
283 }
284
285 q = conv (n, itoa_buf, sizeof (itoa_buf));
286 digits = strlen (q);
287
288 /* Select a width if none was specified. The idea here is to always
289 print something. */
290
291 if (w == 0)
292 w = ((digits < m) ? m : digits);
293
294 p = write_block (dtp, w);
295 if (p == NULL)
296 return;
297
298 nzero = 0;
299 if (digits < m)
300 nzero = m - digits;
301
302 /* See if things will work. */
303
304 nblank = w - (nzero + digits);
305
306 if (nblank < 0)
307 {
308 star_fill (p, w);
309 goto done;
310 }
311
312
313 if (!dtp->u.p.no_leading_blank)
314 {
315 memset (p, ' ', nblank);
316 p += nblank;
317 memset (p, '0', nzero);
318 p += nzero;
319 memcpy (p, q, digits);
320 }
321 else
322 {
323 memset (p, '0', nzero);
324 p += nzero;
325 memcpy (p, q, digits);
326 p += digits;
327 memset (p, ' ', nblank);
328 dtp->u.p.no_leading_blank = 0;
329 }
330
331 done:
332 return;
333 }
334
335 static void
336 write_decimal (st_parameter_dt *dtp, const fnode *f, const char *source,
337 int len,
338 const char *(*conv) (GFC_INTEGER_LARGEST, char *, size_t))
339 {
340 GFC_INTEGER_LARGEST n = 0;
341 int w, m, digits, nsign, nzero, nblank;
342 char *p;
343 const char *q;
344 sign_t sign;
345 char itoa_buf[GFC_BTOA_BUF_SIZE];
346
347 w = f->u.integer.w;
348 m = f->format == FMT_G ? -1 : f->u.integer.m;
349
350 n = extract_int (source, len);
351
352 /* Special case: */
353 if (m == 0 && n == 0)
354 {
355 if (w == 0)
356 w = 1;
357
358 p = write_block (dtp, w);
359 if (p == NULL)
360 return;
361
362 memset (p, ' ', w);
363 goto done;
364 }
365
366 sign = calculate_sign (dtp, n < 0);
367 if (n < 0)
368 n = -n;
369
370 nsign = sign == S_NONE ? 0 : 1;
371 q = conv (n, itoa_buf, sizeof (itoa_buf));
372
373 digits = strlen (q);
374
375 /* Select a width if none was specified. The idea here is to always
376 print something. */
377
378 if (w == 0)
379 w = ((digits < m) ? m : digits) + nsign;
380
381 p = write_block (dtp, w);
382 if (p == NULL)
383 return;
384
385 nzero = 0;
386 if (digits < m)
387 nzero = m - digits;
388
389 /* See if things will work. */
390
391 nblank = w - (nsign + nzero + digits);
392
393 if (nblank < 0)
394 {
395 star_fill (p, w);
396 goto done;
397 }
398
399 memset (p, ' ', nblank);
400 p += nblank;
401
402 switch (sign)
403 {
404 case S_PLUS:
405 *p++ = '+';
406 break;
407 case S_MINUS:
408 *p++ = '-';
409 break;
410 case S_NONE:
411 break;
412 }
413
414 memset (p, '0', nzero);
415 p += nzero;
416
417 memcpy (p, q, digits);
418
419 done:
420 return;
421 }
422
423
424 /* Convert unsigned octal to ascii. */
425
426 static const char *
427 otoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
428 {
429 char *p;
430
431 assert (len >= GFC_OTOA_BUF_SIZE);
432
433 if (n == 0)
434 return "0";
435
436 p = buffer + GFC_OTOA_BUF_SIZE - 1;
437 *p = '\0';
438
439 while (n != 0)
440 {
441 *--p = '0' + (n & 7);
442 n >>= 3;
443 }
444
445 return p;
446 }
447
448
449 /* Convert unsigned binary to ascii. */
450
451 static const char *
452 btoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
453 {
454 char *p;
455
456 assert (len >= GFC_BTOA_BUF_SIZE);
457
458 if (n == 0)
459 return "0";
460
461 p = buffer + GFC_BTOA_BUF_SIZE - 1;
462 *p = '\0';
463
464 while (n != 0)
465 {
466 *--p = '0' + (n & 1);
467 n >>= 1;
468 }
469
470 return p;
471 }
472
473
474 void
475 write_i (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
476 {
477 write_decimal (dtp, f, p, len, (void *) gfc_itoa);
478 }
479
480
481 void
482 write_b (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
483 {
484 write_int (dtp, f, p, len, btoa);
485 }
486
487
488 void
489 write_o (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
490 {
491 write_int (dtp, f, p, len, otoa);
492 }
493
494 void
495 write_z (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
496 {
497 write_int (dtp, f, p, len, xtoa);
498 }
499
500
501 void
502 write_d (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
503 {
504 write_float (dtp, f, p, len);
505 }
506
507
508 void
509 write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
510 {
511 write_float (dtp, f, p, len);
512 }
513
514
515 void
516 write_f (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
517 {
518 write_float (dtp, f, p, len);
519 }
520
521
522 void
523 write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
524 {
525 write_float (dtp, f, p, len);
526 }
527
528
529 void
530 write_es (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
531 {
532 write_float (dtp, f, p, len);
533 }
534
535
536 /* Take care of the X/TR descriptor. */
537
538 void
539 write_x (st_parameter_dt *dtp, int len, int nspaces)
540 {
541 char *p;
542
543 p = write_block (dtp, len);
544 if (p == NULL)
545 return;
546
547 if (nspaces > 0)
548 memset (&p[len - nspaces], ' ', nspaces);
549 }
550
551
552 /* List-directed writing. */
553
554
555 /* Write a single character to the output. Returns nonzero if
556 something goes wrong. */
557
558 static int
559 write_char (st_parameter_dt *dtp, char c)
560 {
561 char *p;
562
563 p = write_block (dtp, 1);
564 if (p == NULL)
565 return 1;
566
567 *p = c;
568
569 return 0;
570 }
571
572
573 /* Write a list-directed logical value. */
574
575 static void
576 write_logical (st_parameter_dt *dtp, const char *source, int length)
577 {
578 write_char (dtp, extract_int (source, length) ? 'T' : 'F');
579 }
580
581
582 /* Write a list-directed integer value. */
583
584 static void
585 write_integer (st_parameter_dt *dtp, const char *source, int length)
586 {
587 char *p;
588 const char *q;
589 int digits;
590 int width;
591 char itoa_buf[GFC_ITOA_BUF_SIZE];
592
593 q = gfc_itoa (extract_int (source, length), itoa_buf, sizeof (itoa_buf));
594
595 switch (length)
596 {
597 case 1:
598 width = 4;
599 break;
600
601 case 2:
602 width = 6;
603 break;
604
605 case 4:
606 width = 11;
607 break;
608
609 case 8:
610 width = 20;
611 break;
612
613 default:
614 width = 0;
615 break;
616 }
617
618 digits = strlen (q);
619
620 if (width < digits)
621 width = digits;
622 p = write_block (dtp, width);
623 if (p == NULL)
624 return;
625 if (dtp->u.p.no_leading_blank)
626 {
627 memcpy (p, q, digits);
628 memset (p + digits, ' ', width - digits);
629 }
630 else
631 {
632 memset (p, ' ', width - digits);
633 memcpy (p + width - digits, q, digits);
634 }
635 }
636
637
638 /* Write a list-directed string. We have to worry about delimiting
639 the strings if the file has been opened in that mode. */
640
641 static void
642 write_character (st_parameter_dt *dtp, const char *source, int length)
643 {
644 int i, extra;
645 char *p, d;
646
647 switch (dtp->u.p.delim_status)
648 {
649 case DELIM_APOSTROPHE:
650 d = '\'';
651 break;
652 case DELIM_QUOTE:
653 d = '"';
654 break;
655 default:
656 d = ' ';
657 break;
658 }
659
660 if (d == ' ')
661 extra = 0;
662 else
663 {
664 extra = 2;
665
666 for (i = 0; i < length; i++)
667 if (source[i] == d)
668 extra++;
669 }
670
671 p = write_block (dtp, length + extra);
672 if (p == NULL)
673 return;
674
675 if (d == ' ')
676 memcpy (p, source, length);
677 else
678 {
679 *p++ = d;
680
681 for (i = 0; i < length; i++)
682 {
683 *p++ = source[i];
684 if (source[i] == d)
685 *p++ = d;
686 }
687
688 *p = d;
689 }
690 }
691
692
693 /* Output a real number with default format.
694 This is 1PG14.7E2 for REAL(4), 1PG23.15E3 for REAL(8),
695 1PG28.19E4 for REAL(10) and 1PG43.34E4 for REAL(16). */
696
697 void
698 write_real (st_parameter_dt *dtp, const char *source, int length)
699 {
700 fnode f ;
701 int org_scale = dtp->u.p.scale_factor;
702 f.format = FMT_G;
703 dtp->u.p.scale_factor = 1;
704 switch (length)
705 {
706 case 4:
707 f.u.real.w = 15;
708 f.u.real.d = 8;
709 f.u.real.e = 2;
710 break;
711 case 8:
712 f.u.real.w = 25;
713 f.u.real.d = 17;
714 f.u.real.e = 3;
715 break;
716 case 10:
717 f.u.real.w = 29;
718 f.u.real.d = 20;
719 f.u.real.e = 4;
720 break;
721 case 16:
722 f.u.real.w = 44;
723 f.u.real.d = 35;
724 f.u.real.e = 4;
725 break;
726 default:
727 internal_error (&dtp->common, "bad real kind");
728 break;
729 }
730 write_float (dtp, &f, source , length);
731 dtp->u.p.scale_factor = org_scale;
732 }
733
734
735 static void
736 write_complex (st_parameter_dt *dtp, const char *source, int kind, size_t size)
737 {
738 char semi_comma = dtp->u.p.decimal_status == DECIMAL_POINT ? ',' : ';';
739
740 if (write_char (dtp, '('))
741 return;
742 write_real (dtp, source, kind);
743
744 if (write_char (dtp, semi_comma))
745 return;
746 write_real (dtp, source + size / 2, kind);
747
748 write_char (dtp, ')');
749 }
750
751
752 /* Write the separator between items. */
753
754 static void
755 write_separator (st_parameter_dt *dtp)
756 {
757 char *p;
758
759 p = write_block (dtp, options.separator_len);
760 if (p == NULL)
761 return;
762
763 memcpy (p, options.separator, options.separator_len);
764 }
765
766
767 /* Write an item with list formatting.
768 TODO: handle skipping to the next record correctly, particularly
769 with strings. */
770
771 static void
772 list_formatted_write_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
773 size_t size)
774 {
775 if (dtp->u.p.current_unit == NULL)
776 return;
777
778 if (dtp->u.p.first_item)
779 {
780 dtp->u.p.first_item = 0;
781 write_char (dtp, ' ');
782 }
783 else
784 {
785 if (type != BT_CHARACTER || !dtp->u.p.char_flag ||
786 dtp->u.p.delim_status != DELIM_NONE)
787 write_separator (dtp);
788 }
789
790 switch (type)
791 {
792 case BT_INTEGER:
793 write_integer (dtp, p, kind);
794 break;
795 case BT_LOGICAL:
796 write_logical (dtp, p, kind);
797 break;
798 case BT_CHARACTER:
799 write_character (dtp, p, kind);
800 break;
801 case BT_REAL:
802 write_real (dtp, p, kind);
803 break;
804 case BT_COMPLEX:
805 write_complex (dtp, p, kind, size);
806 break;
807 default:
808 internal_error (&dtp->common, "list_formatted_write(): Bad type");
809 }
810
811 dtp->u.p.char_flag = (type == BT_CHARACTER);
812 }
813
814
815 void
816 list_formatted_write (st_parameter_dt *dtp, bt type, void *p, int kind,
817 size_t size, size_t nelems)
818 {
819 size_t elem;
820 char *tmp;
821
822 tmp = (char *) p;
823
824 /* Big loop over all the elements. */
825 for (elem = 0; elem < nelems; elem++)
826 {
827 dtp->u.p.item_count++;
828 list_formatted_write_scalar (dtp, type, tmp + size*elem, kind, size);
829 }
830 }
831
832 /* NAMELIST OUTPUT
833
834 nml_write_obj writes a namelist object to the output stream. It is called
835 recursively for derived type components:
836 obj = is the namelist_info for the current object.
837 offset = the offset relative to the address held by the object for
838 derived type arrays.
839 base = is the namelist_info of the derived type, when obj is a
840 component.
841 base_name = the full name for a derived type, including qualifiers
842 if any.
843 The returned value is a pointer to the object beyond the last one
844 accessed, including nested derived types. Notice that the namelist is
845 a linear linked list of objects, including derived types and their
846 components. A tree, of sorts, is implied by the compound names of
847 the derived type components and this is how this function recurses through
848 the list. */
849
850 /* A generous estimate of the number of characters needed to print
851 repeat counts and indices, including commas, asterices and brackets. */
852
853 #define NML_DIGITS 20
854
855 static namelist_info *
856 nml_write_obj (st_parameter_dt *dtp, namelist_info * obj, index_type offset,
857 namelist_info * base, char * base_name)
858 {
859 int rep_ctr;
860 int num;
861 int nml_carry;
862 index_type len;
863 index_type obj_size;
864 index_type nelem;
865 index_type dim_i;
866 index_type clen;
867 index_type elem_ctr;
868 index_type obj_name_len;
869 void * p ;
870 char cup;
871 char * obj_name;
872 char * ext_name;
873 char rep_buff[NML_DIGITS];
874 namelist_info * cmp;
875 namelist_info * retval = obj->next;
876 size_t base_name_len;
877 size_t base_var_name_len;
878 size_t tot_len;
879 unit_delim tmp_delim;
880
881 /* Set the character to be used to separate values
882 to a comma or semi-colon. */
883
884 char semi_comma = dtp->u.p.decimal_status == DECIMAL_POINT ? ',' : ';';
885
886 /* Write namelist variable names in upper case. If a derived type,
887 nothing is output. If a component, base and base_name are set. */
888
889 if (obj->type != GFC_DTYPE_DERIVED)
890 {
891 #ifdef HAVE_CRLF
892 write_character (dtp, "\r\n ", 3);
893 #else
894 write_character (dtp, "\n ", 2);
895 #endif
896 len = 0;
897 if (base)
898 {
899 len =strlen (base->var_name);
900 for (dim_i = 0; dim_i < (index_type) strlen (base_name); dim_i++)
901 {
902 cup = toupper (base_name[dim_i]);
903 write_character (dtp, &cup, 1);
904 }
905 }
906 for (dim_i =len; dim_i < (index_type) strlen (obj->var_name); dim_i++)
907 {
908 cup = toupper (obj->var_name[dim_i]);
909 write_character (dtp, &cup, 1);
910 }
911 write_character (dtp, "=", 1);
912 }
913
914 /* Counts the number of data output on a line, including names. */
915
916 num = 1;
917
918 len = obj->len;
919
920 switch (obj->type)
921 {
922
923 case GFC_DTYPE_REAL:
924 obj_size = size_from_real_kind (len);
925 break;
926
927 case GFC_DTYPE_COMPLEX:
928 obj_size = size_from_complex_kind (len);
929 break;
930
931 case GFC_DTYPE_CHARACTER:
932 obj_size = obj->string_length;
933 break;
934
935 default:
936 obj_size = len;
937 }
938
939 if (obj->var_rank)
940 obj_size = obj->size;
941
942 /* Set the index vector and count the number of elements. */
943
944 nelem = 1;
945 for (dim_i=0; dim_i < obj->var_rank; dim_i++)
946 {
947 obj->ls[dim_i].idx = obj->dim[dim_i].lbound;
948 nelem = nelem * (obj->dim[dim_i].ubound + 1 - obj->dim[dim_i].lbound);
949 }
950
951 /* Main loop to output the data held in the object. */
952
953 rep_ctr = 1;
954 for (elem_ctr = 0; elem_ctr < nelem; elem_ctr++)
955 {
956
957 /* Build the pointer to the data value. The offset is passed by
958 recursive calls to this function for arrays of derived types.
959 Is NULL otherwise. */
960
961 p = (void *)(obj->mem_pos + elem_ctr * obj_size);
962 p += offset;
963
964 /* Check for repeat counts of intrinsic types. */
965
966 if ((elem_ctr < (nelem - 1)) &&
967 (obj->type != GFC_DTYPE_DERIVED) &&
968 !memcmp (p, (void*)(p + obj_size ), obj_size ))
969 {
970 rep_ctr++;
971 }
972
973 /* Execute a repeated output. Note the flag no_leading_blank that
974 is used in the functions used to output the intrinsic types. */
975
976 else
977 {
978 if (rep_ctr > 1)
979 {
980 sprintf(rep_buff, " %d*", rep_ctr);
981 write_character (dtp, rep_buff, strlen (rep_buff));
982 dtp->u.p.no_leading_blank = 1;
983 }
984 num++;
985
986 /* Output the data, if an intrinsic type, or recurse into this
987 routine to treat derived types. */
988
989 switch (obj->type)
990 {
991
992 case GFC_DTYPE_INTEGER:
993 write_integer (dtp, p, len);
994 break;
995
996 case GFC_DTYPE_LOGICAL:
997 write_logical (dtp, p, len);
998 break;
999
1000 case GFC_DTYPE_CHARACTER:
1001 tmp_delim = dtp->u.p.delim_status;
1002 if (dtp->u.p.nml_delim == '"')
1003 dtp->u.p.delim_status = DELIM_QUOTE;
1004 if (dtp->u.p.nml_delim == '\'')
1005 dtp->u.p.delim_status = DELIM_APOSTROPHE;
1006 write_character (dtp, p, obj->string_length);
1007 dtp->u.p.delim_status = tmp_delim;
1008 break;
1009
1010 case GFC_DTYPE_REAL:
1011 write_real (dtp, p, len);
1012 break;
1013
1014 case GFC_DTYPE_COMPLEX:
1015 dtp->u.p.no_leading_blank = 0;
1016 num++;
1017 write_complex (dtp, p, len, obj_size);
1018 break;
1019
1020 case GFC_DTYPE_DERIVED:
1021
1022 /* To treat a derived type, we need to build two strings:
1023 ext_name = the name, including qualifiers that prepends
1024 component names in the output - passed to
1025 nml_write_obj.
1026 obj_name = the derived type name with no qualifiers but %
1027 appended. This is used to identify the
1028 components. */
1029
1030 /* First ext_name => get length of all possible components */
1031
1032 base_name_len = base_name ? strlen (base_name) : 0;
1033 base_var_name_len = base ? strlen (base->var_name) : 0;
1034 ext_name = (char*)get_mem ( base_name_len
1035 + base_var_name_len
1036 + strlen (obj->var_name)
1037 + obj->var_rank * NML_DIGITS
1038 + 1);
1039
1040 memcpy (ext_name, base_name, base_name_len);
1041 clen = strlen (obj->var_name + base_var_name_len);
1042 memcpy (ext_name + base_name_len,
1043 obj->var_name + base_var_name_len, clen);
1044
1045 /* Append the qualifier. */
1046
1047 tot_len = base_name_len + clen;
1048 for (dim_i = 0; dim_i < obj->var_rank; dim_i++)
1049 {
1050 if (!dim_i)
1051 {
1052 ext_name[tot_len] = '(';
1053 tot_len++;
1054 }
1055 sprintf (ext_name + tot_len, "%d", (int) obj->ls[dim_i].idx);
1056 tot_len += strlen (ext_name + tot_len);
1057 ext_name[tot_len] = (dim_i == obj->var_rank - 1) ? ')' : ',';
1058 tot_len++;
1059 }
1060
1061 ext_name[tot_len] = '\0';
1062
1063 /* Now obj_name. */
1064
1065 obj_name_len = strlen (obj->var_name) + 1;
1066 obj_name = get_mem (obj_name_len+1);
1067 memcpy (obj_name, obj->var_name, obj_name_len-1);
1068 memcpy (obj_name + obj_name_len-1, "%", 2);
1069
1070 /* Now loop over the components. Update the component pointer
1071 with the return value from nml_write_obj => this loop jumps
1072 past nested derived types. */
1073
1074 for (cmp = obj->next;
1075 cmp && !strncmp (cmp->var_name, obj_name, obj_name_len);
1076 cmp = retval)
1077 {
1078 retval = nml_write_obj (dtp, cmp,
1079 (index_type)(p - obj->mem_pos),
1080 obj, ext_name);
1081 }
1082
1083 free_mem (obj_name);
1084 free_mem (ext_name);
1085 goto obj_loop;
1086
1087 default:
1088 internal_error (&dtp->common, "Bad type for namelist write");
1089 }
1090
1091 /* Reset the leading blank suppression, write a comma (or semi-colon)
1092 and, if 5 values have been output, write a newline and advance
1093 to column 2. Reset the repeat counter. */
1094
1095 dtp->u.p.no_leading_blank = 0;
1096 write_character (dtp, &semi_comma, 1);
1097 if (num > 5)
1098 {
1099 num = 0;
1100 #ifdef HAVE_CRLF
1101 write_character (dtp, "\r\n ", 3);
1102 #else
1103 write_character (dtp, "\n ", 2);
1104 #endif
1105 }
1106 rep_ctr = 1;
1107 }
1108
1109 /* Cycle through and increment the index vector. */
1110
1111 obj_loop:
1112
1113 nml_carry = 1;
1114 for (dim_i = 0; nml_carry && (dim_i < obj->var_rank); dim_i++)
1115 {
1116 obj->ls[dim_i].idx += nml_carry ;
1117 nml_carry = 0;
1118 if (obj->ls[dim_i].idx > (ssize_t)obj->dim[dim_i].ubound)
1119 {
1120 obj->ls[dim_i].idx = obj->dim[dim_i].lbound;
1121 nml_carry = 1;
1122 }
1123 }
1124 }
1125
1126 /* Return a pointer beyond the furthest object accessed. */
1127
1128 return retval;
1129 }
1130
1131 /* This is the entry function for namelist writes. It outputs the name
1132 of the namelist and iterates through the namelist by calls to
1133 nml_write_obj. The call below has dummys in the arguments used in
1134 the treatment of derived types. */
1135
1136 void
1137 namelist_write (st_parameter_dt *dtp)
1138 {
1139 namelist_info * t1, *t2, *dummy = NULL;
1140 index_type i;
1141 index_type dummy_offset = 0;
1142 char c;
1143 char * dummy_name = NULL;
1144 unit_delim tmp_delim;
1145
1146 /* Set the delimiter for namelist output. */
1147
1148 tmp_delim = dtp->u.p.delim_status;
1149 switch (tmp_delim)
1150 {
1151 case (DELIM_QUOTE):
1152 dtp->u.p.nml_delim = '"';
1153 break;
1154
1155 case (DELIM_APOSTROPHE):
1156 dtp->u.p.nml_delim = '\'';
1157 break;
1158
1159 default:
1160 dtp->u.p.nml_delim = '\0';
1161 break;
1162 }
1163
1164 /* Temporarily disable namelist delimters. */
1165 dtp->u.p.delim_status = DELIM_NONE;
1166
1167 write_character (dtp, "&", 1);
1168
1169 /* Write namelist name in upper case - f95 std. */
1170 for (i = 0 ;i < dtp->namelist_name_len ;i++ )
1171 {
1172 c = toupper (dtp->namelist_name[i]);
1173 write_character (dtp, &c ,1);
1174 }
1175
1176 if (dtp->u.p.ionml != NULL)
1177 {
1178 t1 = dtp->u.p.ionml;
1179 while (t1 != NULL)
1180 {
1181 t2 = t1;
1182 t1 = nml_write_obj (dtp, t2, dummy_offset, dummy, dummy_name);
1183 }
1184 }
1185
1186 #ifdef HAVE_CRLF
1187 write_character (dtp, " /\r\n", 5);
1188 #else
1189 write_character (dtp, " /\n", 4);
1190 #endif
1191
1192 /* Restore the original delimiter. */
1193 dtp->u.p.delim_status = tmp_delim;
1194 }
1195
1196 #undef NML_DIGITS