1 /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
4 This file is part of the GNU Fortran 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 3, 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 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
26 /* Implement the non-IOLENGTH variant of the INQUIRY statement */
34 static const char yes
[] = "YES", no
[] = "NO", undefined
[] = "UNDEFINED";
37 /* inquire_via_unit()-- Inquiry via unit number. The unit might not exist. */
40 inquire_via_unit (st_parameter_inquire
*iqp
, gfc_unit
*u
)
43 GFC_INTEGER_4 cf
= iqp
->common
.flags
;
45 if (iqp
->common
.unit
== GFC_INTERNAL_UNIT
||
46 iqp
->common
.unit
== GFC_INTERNAL_UNIT4
||
47 (u
!= NULL
&& u
->internal_unit_kind
!= 0))
48 generate_error (&iqp
->common
, LIBERROR_INQUIRE_INTERNAL_UNIT
, NULL
);
50 if ((cf
& IOPARM_INQUIRE_HAS_EXIST
) != 0)
51 *iqp
->exist
= (u
!= NULL
&&
52 iqp
->common
.unit
!= GFC_INTERNAL_UNIT
&&
53 iqp
->common
.unit
!= GFC_INTERNAL_UNIT4
)
54 || (iqp
->common
.unit
>= 0);
56 if ((cf
& IOPARM_INQUIRE_HAS_OPENED
) != 0)
57 *iqp
->opened
= (u
!= NULL
);
59 if ((cf
& IOPARM_INQUIRE_HAS_NUMBER
) != 0)
60 *iqp
->number
= (u
!= NULL
) ? u
->unit_number
: -1;
62 if ((cf
& IOPARM_INQUIRE_HAS_NAMED
) != 0)
63 *iqp
->named
= (u
!= NULL
&& u
->flags
.status
!= STATUS_SCRATCH
);
65 if ((cf
& IOPARM_INQUIRE_HAS_NAME
) != 0
66 && u
!= NULL
&& u
->flags
.status
!= STATUS_SCRATCH
)
68 #if defined(HAVE_TTYNAME_R) || defined(HAVE_TTYNAME)
69 if (u
->unit_number
== options
.stdin_unit
70 || u
->unit_number
== options
.stdout_unit
71 || u
->unit_number
== options
.stderr_unit
)
73 int err
= stream_ttyname (u
->s
, iqp
->name
, iqp
->name_len
);
76 gfc_charlen_type tmplen
= strlen (iqp
->name
);
77 if (iqp
->name_len
> tmplen
)
78 memset (&iqp
->name
[tmplen
], ' ', iqp
->name_len
- tmplen
);
80 else /* If ttyname does not work, go with the default. */
81 cf_strcpy (iqp
->name
, iqp
->name_len
, u
->filename
);
84 cf_strcpy (iqp
->name
, iqp
->name_len
, u
->filename
);
85 #elif defined __MINGW32__
86 if (u
->unit_number
== options
.stdin_unit
)
87 fstrcpy (iqp
->name
, iqp
->name_len
, "CONIN$", sizeof("CONIN$"));
88 else if (u
->unit_number
== options
.stdout_unit
)
89 fstrcpy (iqp
->name
, iqp
->name_len
, "CONOUT$", sizeof("CONOUT$"));
90 else if (u
->unit_number
== options
.stderr_unit
)
91 fstrcpy (iqp
->name
, iqp
->name_len
, "CONERR$", sizeof("CONERR$"));
93 cf_strcpy (iqp
->name
, iqp
->name_len
, u
->filename
);
95 cf_strcpy (iqp
->name
, iqp
->name_len
, u
->filename
);
99 if ((cf
& IOPARM_INQUIRE_HAS_ACCESS
) != 0)
104 switch (u
->flags
.access
)
106 case ACCESS_SEQUENTIAL
:
116 internal_error (&iqp
->common
, "inquire_via_unit(): Bad access");
119 cf_strcpy (iqp
->access
, iqp
->access_len
, p
);
122 if ((cf
& IOPARM_INQUIRE_HAS_SEQUENTIAL
) != 0)
125 p
= inquire_sequential (NULL
, 0);
127 switch (u
->flags
.access
)
133 case ACCESS_SEQUENTIAL
:
137 internal_error (&iqp
->common
, "inquire_via_unit(): Bad access");
140 cf_strcpy (iqp
->sequential
, iqp
->sequential_len
, p
);
143 if ((cf
& IOPARM_INQUIRE_HAS_DIRECT
) != 0)
146 p
= inquire_direct (NULL
, 0);
148 switch (u
->flags
.access
)
150 case ACCESS_SEQUENTIAL
:
158 internal_error (&iqp
->common
, "inquire_via_unit(): Bad access");
161 cf_strcpy (iqp
->direct
, iqp
->direct_len
, p
);
164 if ((cf
& IOPARM_INQUIRE_HAS_FORM
) != 0)
169 switch (u
->flags
.form
)
174 case FORM_UNFORMATTED
:
178 internal_error (&iqp
->common
, "inquire_via_unit(): Bad form");
181 cf_strcpy (iqp
->form
, iqp
->form_len
, p
);
184 if ((cf
& IOPARM_INQUIRE_HAS_FORMATTED
) != 0)
187 p
= inquire_formatted (NULL
, 0);
189 switch (u
->flags
.form
)
194 case FORM_UNFORMATTED
:
198 internal_error (&iqp
->common
, "inquire_via_unit(): Bad form");
201 cf_strcpy (iqp
->formatted
, iqp
->formatted_len
, p
);
204 if ((cf
& IOPARM_INQUIRE_HAS_UNFORMATTED
) != 0)
207 p
= inquire_unformatted (NULL
, 0);
209 switch (u
->flags
.form
)
214 case FORM_UNFORMATTED
:
218 internal_error (&iqp
->common
, "inquire_via_unit(): Bad form");
221 cf_strcpy (iqp
->unformatted
, iqp
->unformatted_len
, p
);
224 if ((cf
& IOPARM_INQUIRE_HAS_RECL_OUT
) != 0)
225 /* F2018 (N2137) 12.10.2.26: If there is no connection, recl is
226 assigned the value -1. */
227 *iqp
->recl_out
= (u
!= NULL
) ? u
->recl
: -1;
229 if ((cf
& IOPARM_INQUIRE_HAS_STRM_POS_OUT
) != 0)
230 *iqp
->strm_pos_out
= (u
!= NULL
) ? u
->strm_pos
: 0;
232 if ((cf
& IOPARM_INQUIRE_HAS_NEXTREC
) != 0)
234 /* This only makes sense in the context of DIRECT access. */
235 if (u
!= NULL
&& u
->flags
.access
== ACCESS_DIRECT
)
236 *iqp
->nextrec
= u
->last_record
+ 1;
241 if ((cf
& IOPARM_INQUIRE_HAS_BLANK
) != 0)
243 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
246 switch (u
->flags
.blank
)
255 internal_error (&iqp
->common
, "inquire_via_unit(): Bad blank");
258 cf_strcpy (iqp
->blank
, iqp
->blank_len
, p
);
261 if ((cf
& IOPARM_INQUIRE_HAS_PAD
) != 0)
263 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
266 switch (u
->flags
.pad
)
275 internal_error (&iqp
->common
, "inquire_via_unit(): Bad pad");
278 cf_strcpy (iqp
->pad
, iqp
->pad_len
, p
);
281 if (cf
& IOPARM_INQUIRE_HAS_FLAGS2
)
283 GFC_INTEGER_4 cf2
= iqp
->flags2
;
285 if ((cf2
& IOPARM_INQUIRE_HAS_ENCODING
) != 0)
287 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
290 switch (u
->flags
.encoding
)
292 case ENCODING_DEFAULT
:
299 internal_error (&iqp
->common
, "inquire_via_unit(): Bad encoding");
302 cf_strcpy (iqp
->encoding
, iqp
->encoding_len
, p
);
305 if ((cf2
& IOPARM_INQUIRE_HAS_DECIMAL
) != 0)
307 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
310 switch (u
->flags
.decimal
)
319 internal_error (&iqp
->common
, "inquire_via_unit(): Bad comma");
322 cf_strcpy (iqp
->decimal
, iqp
->decimal_len
, p
);
325 if ((cf2
& IOPARM_INQUIRE_HAS_ASYNCHRONOUS
) != 0)
331 switch (u
->flags
.async
)
340 internal_error (&iqp
->common
, "inquire_via_unit(): Bad async");
343 cf_strcpy (iqp
->asynchronous
, iqp
->asynchronous_len
, p
);
346 if ((cf2
& IOPARM_INQUIRE_HAS_PENDING
) != 0)
348 if (!ASYNC_IO
|| u
->au
== NULL
)
352 LOCK (&(u
->au
->lock
));
353 if ((cf2
& IOPARM_INQUIRE_HAS_ID
) != 0)
357 *(iqp
->pending
) = id
> u
->au
->id
.low
;
361 *(iqp
->pending
) = ! u
->au
->empty
;
363 UNLOCK (&(u
->au
->lock
));
367 if ((cf2
& IOPARM_INQUIRE_HAS_SIGN
) != 0)
372 switch (u
->flags
.sign
)
374 case SIGN_PROCDEFINED
:
375 p
= "PROCESSOR_DEFINED";
384 internal_error (&iqp
->common
, "inquire_via_unit(): Bad sign");
387 cf_strcpy (iqp
->sign
, iqp
->sign_len
, p
);
390 if ((cf2
& IOPARM_INQUIRE_HAS_ROUND
) != 0)
395 switch (u
->flags
.round
)
409 case ROUND_COMPATIBLE
:
412 case ROUND_PROCDEFINED
:
413 p
= "PROCESSOR_DEFINED";
416 internal_error (&iqp
->common
, "inquire_via_unit(): Bad round");
419 cf_strcpy (iqp
->round
, iqp
->round_len
, p
);
422 if ((cf2
& IOPARM_INQUIRE_HAS_SIZE
) != 0)
429 *iqp
->size
= ssize (u
->s
);
433 if ((cf2
& IOPARM_INQUIRE_HAS_IQSTREAM
) != 0)
438 switch (u
->flags
.access
)
440 case ACCESS_SEQUENTIAL
:
448 internal_error (&iqp
->common
, "inquire_via_unit(): Bad pad");
451 cf_strcpy (iqp
->iqstream
, iqp
->iqstream_len
, p
);
454 if ((cf2
& IOPARM_INQUIRE_HAS_SHARE
) != 0)
459 switch (u
->flags
.share
)
467 case SHARE_UNSPECIFIED
:
471 internal_error (&iqp
->common
,
472 "inquire_via_unit(): Bad share");
476 cf_strcpy (iqp
->share
, iqp
->share_len
, p
);
479 if ((cf2
& IOPARM_INQUIRE_HAS_CC
) != 0)
499 internal_error (&iqp
->common
, "inquire_via_unit(): Bad cc");
503 cf_strcpy (iqp
->cc
, iqp
->cc_len
, p
);
507 if ((cf
& IOPARM_INQUIRE_HAS_POSITION
) != 0)
509 if (u
== NULL
|| u
->flags
.access
== ACCESS_DIRECT
)
513 /* If the position is unspecified, check if we can figure
514 out whether it's at the beginning or end. */
515 if (u
->flags
.position
== POSITION_UNSPECIFIED
)
517 gfc_offset cur
= stell (u
->s
);
519 u
->flags
.position
= POSITION_REWIND
;
520 else if (cur
!= -1 && (ssize (u
->s
) == cur
))
521 u
->flags
.position
= POSITION_APPEND
;
523 switch (u
->flags
.position
)
525 case POSITION_REWIND
:
528 case POSITION_APPEND
:
535 /* If the position has changed and is not rewind or
536 append, it must be set to a processor-dependent
542 cf_strcpy (iqp
->position
, iqp
->position_len
, p
);
545 if ((cf
& IOPARM_INQUIRE_HAS_ACTION
) != 0)
550 switch (u
->flags
.action
)
558 case ACTION_READWRITE
:
562 internal_error (&iqp
->common
, "inquire_via_unit(): Bad action");
565 cf_strcpy (iqp
->action
, iqp
->action_len
, p
);
568 if ((cf
& IOPARM_INQUIRE_HAS_READ
) != 0)
570 p
= (!u
|| u
->flags
.action
== ACTION_WRITE
) ? no
: yes
;
571 cf_strcpy (iqp
->read
, iqp
->read_len
, p
);
574 if ((cf
& IOPARM_INQUIRE_HAS_WRITE
) != 0)
576 p
= (!u
|| u
->flags
.action
== ACTION_READ
) ? no
: yes
;
577 cf_strcpy (iqp
->write
, iqp
->write_len
, p
);
580 if ((cf
& IOPARM_INQUIRE_HAS_READWRITE
) != 0)
582 p
= (!u
|| u
->flags
.action
!= ACTION_READWRITE
) ? no
: yes
;
583 cf_strcpy (iqp
->readwrite
, iqp
->readwrite_len
, p
);
586 if ((cf
& IOPARM_INQUIRE_HAS_DELIM
) != 0)
588 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
591 switch (u
->flags
.delim
)
594 case DELIM_UNSPECIFIED
:
600 case DELIM_APOSTROPHE
:
604 internal_error (&iqp
->common
, "inquire_via_unit(): Bad delim");
607 cf_strcpy (iqp
->delim
, iqp
->delim_len
, p
);
610 if ((cf
& IOPARM_INQUIRE_HAS_PAD
) != 0)
612 if (u
== NULL
|| u
->flags
.form
!= FORM_FORMATTED
)
615 switch (u
->flags
.pad
)
624 internal_error (&iqp
->common
, "inquire_via_unit(): Bad pad");
627 cf_strcpy (iqp
->pad
, iqp
->pad_len
, p
);
630 if ((cf
& IOPARM_INQUIRE_HAS_CONVERT
) != 0)
635 switch (u
->flags
.convert
)
637 case GFC_CONVERT_NATIVE
:
638 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "BIG_ENDIAN" : "LITTLE_ENDIAN";
641 case GFC_CONVERT_SWAP
:
642 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "LITTLE_ENDIAN" : "BIG_ENDIAN";
645 #ifdef HAVE_GFC_REAL_17
646 case GFC_CONVERT_NATIVE
| GFC_CONVERT_R16_IEEE
:
647 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "BIG_ENDIAN,R16_IEEE" : "LITTLE_ENDIAN,R16_IEEE";
650 case GFC_CONVERT_SWAP
| GFC_CONVERT_R16_IEEE
:
651 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "LITTLE_ENDIAN,R16_IEEE" : "BIG_ENDIAN,R16_IEEE";
654 case GFC_CONVERT_NATIVE
| GFC_CONVERT_R16_IBM
:
655 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "BIG_ENDIAN,R16_IBM" : "LITTLE_ENDIAN,R16_IBM";
658 case GFC_CONVERT_SWAP
| GFC_CONVERT_R16_IBM
:
659 p
= __BYTE_ORDER__
== __ORDER_BIG_ENDIAN__
? "LITTLE_ENDIAN,R16_IBM" : "BIG_ENDIAN,R16_IBM";
664 internal_error (&iqp
->common
, "inquire_via_unit(): Bad convert");
667 cf_strcpy (iqp
->convert
, iqp
->convert_len
, p
);
672 /* inquire_via_filename()-- Inquiry via filename. This subroutine is
673 only used if the filename is *not* connected to a unit number. */
676 inquire_via_filename (st_parameter_inquire
*iqp
)
679 GFC_INTEGER_4 cf
= iqp
->common
.flags
;
681 if ((cf
& IOPARM_INQUIRE_HAS_EXIST
) != 0)
682 *iqp
->exist
= file_exists (iqp
->file
, iqp
->file_len
);
684 if ((cf
& IOPARM_INQUIRE_HAS_OPENED
) != 0)
687 if ((cf
& IOPARM_INQUIRE_HAS_NUMBER
) != 0)
690 if ((cf
& IOPARM_INQUIRE_HAS_NAMED
) != 0)
693 if ((cf
& IOPARM_INQUIRE_HAS_NAME
) != 0)
694 fstrcpy (iqp
->name
, iqp
->name_len
, iqp
->file
, iqp
->file_len
);
696 if ((cf
& IOPARM_INQUIRE_HAS_ACCESS
) != 0)
697 cf_strcpy (iqp
->access
, iqp
->access_len
, undefined
);
699 if ((cf
& IOPARM_INQUIRE_HAS_SEQUENTIAL
) != 0)
702 cf_strcpy (iqp
->sequential
, iqp
->sequential_len
, p
);
705 if ((cf
& IOPARM_INQUIRE_HAS_DIRECT
) != 0)
708 cf_strcpy (iqp
->direct
, iqp
->direct_len
, p
);
711 if ((cf
& IOPARM_INQUIRE_HAS_FORM
) != 0)
712 cf_strcpy (iqp
->form
, iqp
->form_len
, undefined
);
714 if ((cf
& IOPARM_INQUIRE_HAS_FORMATTED
) != 0)
717 cf_strcpy (iqp
->formatted
, iqp
->formatted_len
, p
);
720 if ((cf
& IOPARM_INQUIRE_HAS_UNFORMATTED
) != 0)
723 cf_strcpy (iqp
->unformatted
, iqp
->unformatted_len
, p
);
726 if ((cf
& IOPARM_INQUIRE_HAS_RECL_OUT
) != 0)
727 /* F2018 (N2137) 12.10.2.26: If there is no connection, recl is
728 assigned the value -1. */
731 if ((cf
& IOPARM_INQUIRE_HAS_NEXTREC
) != 0)
734 if ((cf
& IOPARM_INQUIRE_HAS_BLANK
) != 0)
735 cf_strcpy (iqp
->blank
, iqp
->blank_len
, undefined
);
737 if ((cf
& IOPARM_INQUIRE_HAS_PAD
) != 0)
738 cf_strcpy (iqp
->pad
, iqp
->pad_len
, undefined
);
740 if (cf
& IOPARM_INQUIRE_HAS_FLAGS2
)
742 GFC_INTEGER_4 cf2
= iqp
->flags2
;
744 if ((cf2
& IOPARM_INQUIRE_HAS_ENCODING
) != 0)
745 cf_strcpy (iqp
->encoding
, iqp
->encoding_len
, undefined
);
747 if ((cf2
& IOPARM_INQUIRE_HAS_DELIM
) != 0)
748 cf_strcpy (iqp
->delim
, iqp
->delim_len
, undefined
);
750 if ((cf2
& IOPARM_INQUIRE_HAS_DECIMAL
) != 0)
751 cf_strcpy (iqp
->decimal
, iqp
->decimal_len
, undefined
);
753 if ((cf2
& IOPARM_INQUIRE_HAS_DELIM
) != 0)
754 cf_strcpy (iqp
->delim
, iqp
->delim_len
, undefined
);
756 if ((cf2
& IOPARM_INQUIRE_HAS_PAD
) != 0)
757 cf_strcpy (iqp
->pad
, iqp
->pad_len
, undefined
);
759 if ((cf2
& IOPARM_INQUIRE_HAS_ENCODING
) != 0)
760 cf_strcpy (iqp
->encoding
, iqp
->encoding_len
, undefined
);
762 if ((cf2
& IOPARM_INQUIRE_HAS_SIZE
) != 0)
763 *iqp
->size
= file_size (iqp
->file
, iqp
->file_len
);
765 if ((cf2
& IOPARM_INQUIRE_HAS_IQSTREAM
) != 0)
766 cf_strcpy (iqp
->iqstream
, iqp
->iqstream_len
, "UNKNOWN");
768 if ((cf2
& IOPARM_INQUIRE_HAS_SHARE
) != 0)
769 cf_strcpy (iqp
->share
, iqp
->share_len
, "UNKNOWN");
771 if ((cf2
& IOPARM_INQUIRE_HAS_CC
) != 0)
772 cf_strcpy (iqp
->cc
, iqp
->cc_len
, "UNKNOWN");
775 if ((cf
& IOPARM_INQUIRE_HAS_POSITION
) != 0)
776 cf_strcpy (iqp
->position
, iqp
->position_len
, undefined
);
778 if ((cf
& IOPARM_INQUIRE_HAS_ACCESS
) != 0)
779 cf_strcpy (iqp
->access
, iqp
->access_len
, undefined
);
781 if ((cf
& IOPARM_INQUIRE_HAS_READ
) != 0)
783 p
= inquire_read (iqp
->file
, iqp
->file_len
);
784 cf_strcpy (iqp
->read
, iqp
->read_len
, p
);
787 if ((cf
& IOPARM_INQUIRE_HAS_WRITE
) != 0)
789 p
= inquire_write (iqp
->file
, iqp
->file_len
);
790 cf_strcpy (iqp
->write
, iqp
->write_len
, p
);
793 if ((cf
& IOPARM_INQUIRE_HAS_READWRITE
) != 0)
795 p
= inquire_read (iqp
->file
, iqp
->file_len
);
796 cf_strcpy (iqp
->readwrite
, iqp
->readwrite_len
, p
);
801 /* Library entry point for the INQUIRE statement (non-IOLENGTH
804 extern void st_inquire (st_parameter_inquire
*);
805 export_proto(st_inquire
);
808 st_inquire (st_parameter_inquire
*iqp
)
812 library_start (&iqp
->common
);
814 if ((iqp
->common
.flags
& IOPARM_INQUIRE_HAS_FILE
) == 0)
816 u
= find_unit (iqp
->common
.unit
);
817 inquire_via_unit (iqp
, u
);
821 u
= find_file (iqp
->file
, iqp
->file_len
);
823 inquire_via_filename (iqp
);
825 inquire_via_unit (iqp
, u
);