1 //===-- runtime/io-stmt.cpp -----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "connection.h"
11 #include "emit-encoded.h"
16 #include "flang/Runtime/memory.h"
21 #include <type_traits>
23 namespace Fortran::runtime::io
{
24 RT_OFFLOAD_API_GROUP_BEGIN
26 bool IoStatementBase::Emit(const char *, std::size_t, std::size_t) {
30 std::size_t IoStatementBase::GetNextInputBytes(const char *&p
) {
35 std::size_t IoStatementBase::ViewBytesInRecord(
36 const char *&p
, bool forward
) const {
41 bool IoStatementBase::AdvanceRecord(int) { return false; }
43 void IoStatementBase::BackspaceRecord() {}
45 bool IoStatementBase::Receive(char *, std::size_t, std::size_t) {
49 Fortran::common::optional
<DataEdit
> IoStatementBase::GetNextDataEdit(
50 IoStatementState
&, int) {
51 return Fortran::common::nullopt
;
54 bool IoStatementBase::BeginReadingRecord() { return true; }
56 void IoStatementBase::FinishReadingRecord() {}
58 void IoStatementBase::HandleAbsolutePosition(std::int64_t) {}
60 void IoStatementBase::HandleRelativePosition(std::int64_t) {}
62 std::int64_t IoStatementBase::InquirePos() { return 0; }
64 ExternalFileUnit
*IoStatementBase::GetExternalFileUnit() const {
68 bool IoStatementBase::Inquire(InquiryKeywordHash
, char *, std::size_t) {
72 bool IoStatementBase::Inquire(InquiryKeywordHash
, bool &) { return false; }
74 bool IoStatementBase::Inquire(InquiryKeywordHash
, std::int64_t, bool &) {
78 bool IoStatementBase::Inquire(InquiryKeywordHash
, std::int64_t &) {
82 void IoStatementBase::BadInquiryKeywordHashCrash(InquiryKeywordHash inquiry
) {
84 const char *decode
{InquiryKeywordHashDecode(buffer
, sizeof buffer
, inquiry
)};
85 Crash("Bad InquiryKeywordHash 0x%x (%s)", inquiry
,
86 decode
? decode
: "(cannot decode)");
89 template <Direction
DIR>
90 InternalIoStatementState
<DIR>::InternalIoStatementState(
91 Buffer scalar
, std::size_t length
, const char *sourceFile
, int sourceLine
)
92 : IoStatementBase
{sourceFile
, sourceLine
}, unit_
{scalar
, length
, 1} {}
94 template <Direction
DIR>
95 InternalIoStatementState
<DIR>::InternalIoStatementState(
96 const Descriptor
&d
, const char *sourceFile
, int sourceLine
)
97 : IoStatementBase
{sourceFile
, sourceLine
}, unit_
{d
, *this} {}
99 template <Direction
DIR>
100 bool InternalIoStatementState
<DIR>::Emit(
101 const char *data
, std::size_t bytes
, std::size_t /*elementBytes*/) {
102 if constexpr (DIR == Direction::Input
) {
103 Crash("InternalIoStatementState<Direction::Input>::Emit() called");
106 return unit_
.Emit(data
, bytes
, *this);
109 template <Direction
DIR>
110 std::size_t InternalIoStatementState
<DIR>::GetNextInputBytes(const char *&p
) {
111 return unit_
.GetNextInputBytes(p
, *this);
114 // InternalIoStatementState<DIR>::ViewBytesInRecord() not needed or defined
116 template <Direction
DIR>
117 bool InternalIoStatementState
<DIR>::AdvanceRecord(int n
) {
119 if (!unit_
.AdvanceRecord(*this)) {
126 template <Direction
DIR> void InternalIoStatementState
<DIR>::BackspaceRecord() {
127 unit_
.BackspaceRecord(*this);
130 template <Direction
DIR> int InternalIoStatementState
<DIR>::EndIoStatement() {
131 auto result
{IoStatementBase::EndIoStatement()};
138 template <Direction
DIR>
139 void InternalIoStatementState
<DIR>::HandleAbsolutePosition(std::int64_t n
) {
140 return unit_
.HandleAbsolutePosition(n
);
143 template <Direction
DIR>
144 void InternalIoStatementState
<DIR>::HandleRelativePosition(std::int64_t n
) {
145 return unit_
.HandleRelativePosition(n
);
148 template <Direction
DIR>
149 std::int64_t InternalIoStatementState
<DIR>::InquirePos() {
150 return unit_
.InquirePos();
153 template <Direction
DIR, typename CHAR
>
155 InternalFormattedIoStatementState
<DIR, CHAR
>::InternalFormattedIoStatementState(
156 Buffer buffer
, std::size_t length
, const CharType
*format
,
157 std::size_t formatLength
, const Descriptor
*formatDescriptor
,
158 const char *sourceFile
, int sourceLine
)
159 : InternalIoStatementState
<DIR>{buffer
, length
, sourceFile
, sourceLine
},
160 ioStatementState_
{*this},
161 format_
{*this, format
, formatLength
, formatDescriptor
} {}
163 template <Direction
DIR, typename CHAR
>
165 InternalFormattedIoStatementState
<DIR, CHAR
>::InternalFormattedIoStatementState(
166 const Descriptor
&d
, const CharType
*format
, std::size_t formatLength
,
167 const Descriptor
*formatDescriptor
, const char *sourceFile
, int sourceLine
)
168 : InternalIoStatementState
<DIR>{d
, sourceFile
, sourceLine
},
169 ioStatementState_
{*this},
170 format_
{*this, format
, formatLength
, formatDescriptor
} {}
172 template <Direction
DIR, typename CHAR
>
173 void InternalFormattedIoStatementState
<DIR, CHAR
>::CompleteOperation() {
174 if (!this->completedOperation()) {
175 if constexpr (DIR == Direction::Output
) {
176 format_
.Finish(*this);
177 unit_
.AdvanceRecord(*this);
179 IoStatementBase::CompleteOperation();
183 template <Direction
DIR, typename CHAR
>
184 int InternalFormattedIoStatementState
<DIR, CHAR
>::EndIoStatement() {
186 return InternalIoStatementState
<DIR>::EndIoStatement();
189 template <Direction
DIR>
190 InternalListIoStatementState
<DIR>::InternalListIoStatementState(
191 Buffer buffer
, std::size_t length
, const char *sourceFile
, int sourceLine
)
192 : InternalIoStatementState
<DIR>{buffer
, length
, sourceFile
, sourceLine
},
193 ioStatementState_
{*this} {}
195 template <Direction
DIR>
196 InternalListIoStatementState
<DIR>::InternalListIoStatementState(
197 const Descriptor
&d
, const char *sourceFile
, int sourceLine
)
198 : InternalIoStatementState
<DIR>{d
, sourceFile
, sourceLine
},
199 ioStatementState_
{*this} {}
201 template <Direction
DIR>
202 void InternalListIoStatementState
<DIR>::CompleteOperation() {
203 if (!this->completedOperation()) {
204 if constexpr (DIR == Direction::Output
) {
205 if (unit_
.furthestPositionInRecord
> 0) {
206 unit_
.AdvanceRecord(*this);
209 IoStatementBase::CompleteOperation();
213 template <Direction
DIR>
214 int InternalListIoStatementState
<DIR>::EndIoStatement() {
216 if constexpr (DIR == Direction::Input
) {
217 if (int status
{ListDirectedStatementState
<DIR>::EndIoStatement()};
218 status
!= IostatOk
) {
222 return InternalIoStatementState
<DIR>::EndIoStatement();
225 ExternalIoStatementBase::ExternalIoStatementBase(
226 ExternalFileUnit
&unit
, const char *sourceFile
, int sourceLine
)
227 : IoStatementBase
{sourceFile
, sourceLine
}, unit_
{unit
} {}
229 MutableModes
&ExternalIoStatementBase::mutableModes() {
230 if (const ChildIo
* child
{unit_
.GetChildIo()}) {
231 #if !defined(RT_DEVICE_AVOID_RECURSION)
232 return child
->parent().mutableModes();
234 ReportUnsupportedChildIo();
240 ConnectionState
&ExternalIoStatementBase::GetConnectionState() { return unit_
; }
242 int ExternalIoStatementBase::EndIoStatement() {
244 auto result
{IoStatementBase::EndIoStatement()};
245 #if !defined(RT_USE_PSEUDO_FILE_UNIT)
246 auto unitNumber
{unit_
.unitNumber()};
247 unit_
.EndIoStatement(); // annihilates *this in unit_.u_
249 if (ExternalFileUnit
*
250 toClose
{ExternalFileUnit::LookUpForClose(unitNumber
)}) {
251 toClose
->Close(CloseStatus::Delete
, *this);
252 toClose
->DestroyClosed();
256 // Fetch the unit pointer before *this disappears.
257 ExternalFileUnit
*unitPtr
{&unit_
};
258 // The pseudo file units are dynamically allocated
259 // and are not tracked in the unit map.
260 // They have to be destructed and deallocated here.
261 unitPtr
->~ExternalFileUnit();
267 void ExternalIoStatementBase::SetAsynchronous() {
268 asynchronousID_
= unit().GetAsynchronousId(*this);
271 std::int64_t ExternalIoStatementBase::InquirePos() {
272 return unit_
.InquirePos();
275 void OpenStatementState::set_path(const char *path
, std::size_t length
) {
276 pathLength_
= TrimTrailingSpaces(path
, length
);
277 path_
= SaveDefaultCharacter(path
, pathLength_
, *this);
280 void OpenStatementState::CompleteOperation() {
281 if (completedOperation()) {
285 if (access_
&& *access_
== Access::Direct
) {
286 SignalError("POSITION= may not be set with ACCESS='DIRECT'");
290 if (status_
) { // 12.5.6.10
291 if ((*status_
== OpenStatus::New
|| *status_
== OpenStatus::Replace
) &&
293 SignalError("FILE= required on OPEN with STATUS='NEW' or 'REPLACE'");
294 } else if (*status_
== OpenStatus::Scratch
&& path_
.get()) {
295 SignalError("FILE= may not appear on OPEN with STATUS='SCRATCH'");
298 // F'2023 12.5.6.13 - NEWUNIT= requires either FILE= or STATUS='SCRATCH'
299 if (isNewUnit_
&& !path_
.get() &&
300 status_
.value_or(OpenStatus::Unknown
) != OpenStatus::Scratch
) {
301 SignalError(IostatBadNewUnit
);
302 status_
= OpenStatus::Scratch
; // error recovery
304 if (path_
.get() || wasExtant_
||
305 (status_
&& *status_
== OpenStatus::Scratch
)) {
306 if (unit().OpenUnit(status_
, action_
, position_
.value_or(Position::AsIs
),
307 std::move(path_
), pathLength_
, convert_
, *this)) {
308 wasExtant_
= false; // existing unit was closed
311 unit().OpenAnonymousUnit(
312 status_
, action_
, position_
.value_or(Position::AsIs
), convert_
, *this);
315 if (*access_
!= unit().access
) {
317 SignalError("ACCESS= may not be changed on an open unit");
322 unit().access
= *access_
;
325 if (!unit().isUnformatted
) {
326 unit().isUnformatted
= isUnformatted_
;
328 if (isUnformatted_
&& *isUnformatted_
!= *unit().isUnformatted
) {
330 SignalError("FORM= may not be changed on an open unit");
332 unit().isUnformatted
= *isUnformatted_
;
334 if (!unit().isUnformatted
) {
335 // Set default format (C.7.4 point 2).
336 unit().isUnformatted
= unit().access
!= Access::Sequential
;
338 if (!wasExtant_
&& InError()) {
339 // Release the new unit on failure
342 IoStatementBase::CompleteOperation();
345 int OpenStatementState::EndIoStatement() {
347 return ExternalIoStatementBase::EndIoStatement();
350 int CloseStatementState::EndIoStatement() {
352 int result
{ExternalIoStatementBase::EndIoStatement()};
353 unit().CloseUnit(status_
, *this);
354 unit().DestroyClosed();
358 void NoUnitIoStatementState::CompleteOperation() {
359 SignalPendingError();
360 IoStatementBase::CompleteOperation();
363 int NoUnitIoStatementState::EndIoStatement() {
365 auto result
{IoStatementBase::EndIoStatement()};
370 template <Direction
DIR>
371 ExternalIoStatementState
<DIR>::ExternalIoStatementState(
372 ExternalFileUnit
&unit
, const char *sourceFile
, int sourceLine
)
373 : ExternalIoStatementBase
{unit
, sourceFile
, sourceLine
}, mutableModes_
{
375 if constexpr (DIR == Direction::Output
) {
376 // If the last statement was a non-advancing IO input statement, the unit
377 // furthestPositionInRecord was not advanced, but the positionInRecord may
378 // have been advanced. Advance furthestPositionInRecord here to avoid
379 // overwriting the part of the record that has been read with blanks.
380 unit
.furthestPositionInRecord
=
381 std::max(unit
.furthestPositionInRecord
, unit
.positionInRecord
);
385 template <Direction
DIR>
386 void ExternalIoStatementState
<DIR>::CompleteOperation() {
387 if (completedOperation()) {
390 if constexpr (DIR == Direction::Input
) {
391 BeginReadingRecord(); // in case there were no I/O items
392 if (mutableModes().nonAdvancing
&& !InError()) {
393 unit().leftTabLimit
= unit().furthestPositionInRecord
;
395 FinishReadingRecord();
398 if (mutableModes().nonAdvancing
) {
399 // Make effects of positioning past the last Emit() visible with blanks.
400 if (unit().positionInRecord
> unit().furthestPositionInRecord
) {
401 unit().Emit("", 0, 1, *this); // Emit() will pad
403 unit().leftTabLimit
= unit().positionInRecord
;
405 unit().AdvanceRecord(*this);
407 unit().FlushIfTerminal(*this);
409 return IoStatementBase::CompleteOperation();
412 template <Direction
DIR> int ExternalIoStatementState
<DIR>::EndIoStatement() {
414 return ExternalIoStatementBase::EndIoStatement();
417 template <Direction
DIR>
418 bool ExternalIoStatementState
<DIR>::Emit(
419 const char *data
, std::size_t bytes
, std::size_t elementBytes
) {
420 if constexpr (DIR == Direction::Input
) {
421 Crash("ExternalIoStatementState::Emit(char) called for input statement");
423 return unit().Emit(data
, bytes
, elementBytes
, *this);
426 template <Direction
DIR>
427 std::size_t ExternalIoStatementState
<DIR>::GetNextInputBytes(const char *&p
) {
428 return unit().GetNextInputBytes(p
, *this);
431 template <Direction
DIR>
432 std::size_t ExternalIoStatementState
<DIR>::ViewBytesInRecord(
433 const char *&p
, bool forward
) const {
434 return unit().ViewBytesInRecord(p
, forward
);
437 template <Direction
DIR>
438 bool ExternalIoStatementState
<DIR>::AdvanceRecord(int n
) {
440 if (!unit().AdvanceRecord(*this)) {
447 template <Direction
DIR> void ExternalIoStatementState
<DIR>::BackspaceRecord() {
448 unit().BackspaceRecord(*this);
451 template <Direction
DIR>
452 void ExternalIoStatementState
<DIR>::HandleAbsolutePosition(std::int64_t n
) {
453 return unit().HandleAbsolutePosition(n
);
456 template <Direction
DIR>
457 void ExternalIoStatementState
<DIR>::HandleRelativePosition(std::int64_t n
) {
458 return unit().HandleRelativePosition(n
);
461 template <Direction
DIR>
462 bool ExternalIoStatementState
<DIR>::BeginReadingRecord() {
463 if constexpr (DIR == Direction::Input
) {
464 return unit().BeginReadingRecord(*this);
466 Crash("ExternalIoStatementState<Direction::Output>::BeginReadingRecord() "
472 template <Direction
DIR>
473 void ExternalIoStatementState
<DIR>::FinishReadingRecord() {
474 if constexpr (DIR == Direction::Input
) {
475 unit().FinishReadingRecord(*this);
477 Crash("ExternalIoStatementState<Direction::Output>::FinishReadingRecord() "
482 template <Direction
DIR, typename CHAR
>
483 ExternalFormattedIoStatementState
<DIR, CHAR
>::ExternalFormattedIoStatementState(
484 ExternalFileUnit
&unit
, const CHAR
*format
, std::size_t formatLength
,
485 const Descriptor
*formatDescriptor
, const char *sourceFile
, int sourceLine
)
486 : ExternalIoStatementState
<DIR>{unit
, sourceFile
, sourceLine
},
487 format_
{*this, format
, formatLength
, formatDescriptor
} {}
489 template <Direction
DIR, typename CHAR
>
490 void ExternalFormattedIoStatementState
<DIR, CHAR
>::CompleteOperation() {
491 if (this->completedOperation()) {
494 if constexpr (DIR == Direction::Input
) {
495 this->BeginReadingRecord(); // in case there were no I/O items
497 format_
.Finish(*this);
498 return ExternalIoStatementState
<DIR>::CompleteOperation();
501 template <Direction
DIR, typename CHAR
>
502 int ExternalFormattedIoStatementState
<DIR, CHAR
>::EndIoStatement() {
504 return ExternalIoStatementState
<DIR>::EndIoStatement();
507 Fortran::common::optional
<DataEdit
> IoStatementState::GetNextDataEdit(int n
) {
508 return common::visit(
509 [&](auto &x
) { return x
.get().GetNextDataEdit(*this, n
); }, u_
);
512 bool IoStatementState::Emit(
513 const char *data
, std::size_t bytes
, std::size_t elementBytes
) {
514 return common::visit(
515 [=](auto &x
) { return x
.get().Emit(data
, bytes
, elementBytes
); }, u_
);
518 bool IoStatementState::Receive(
519 char *data
, std::size_t n
, std::size_t elementBytes
) {
520 return common::visit(
521 [=](auto &x
) { return x
.get().Receive(data
, n
, elementBytes
); }, u_
);
524 std::size_t IoStatementState::GetNextInputBytes(const char *&p
) {
525 return common::visit(
526 [&](auto &x
) { return x
.get().GetNextInputBytes(p
); }, u_
);
529 bool IoStatementState::AdvanceRecord(int n
) {
530 return common::visit([=](auto &x
) { return x
.get().AdvanceRecord(n
); }, u_
);
533 void IoStatementState::BackspaceRecord() {
534 common::visit([](auto &x
) { x
.get().BackspaceRecord(); }, u_
);
537 void IoStatementState::HandleRelativePosition(std::int64_t n
) {
538 common::visit([=](auto &x
) { x
.get().HandleRelativePosition(n
); }, u_
);
541 void IoStatementState::HandleAbsolutePosition(std::int64_t n
) {
542 common::visit([=](auto &x
) { x
.get().HandleAbsolutePosition(n
); }, u_
);
545 void IoStatementState::CompleteOperation() {
546 common::visit([](auto &x
) { x
.get().CompleteOperation(); }, u_
);
549 int IoStatementState::EndIoStatement() {
550 return common::visit([](auto &x
) { return x
.get().EndIoStatement(); }, u_
);
553 ConnectionState
&IoStatementState::GetConnectionState() {
554 return common::visit(
555 [](auto &x
) -> ConnectionState
& { return x
.get().GetConnectionState(); },
559 MutableModes
&IoStatementState::mutableModes() {
560 return common::visit(
561 [](auto &x
) -> MutableModes
& { return x
.get().mutableModes(); }, u_
);
564 bool IoStatementState::BeginReadingRecord() {
565 return common::visit(
566 [](auto &x
) { return x
.get().BeginReadingRecord(); }, u_
);
569 IoErrorHandler
&IoStatementState::GetIoErrorHandler() const {
570 return common::visit(
571 [](auto &x
) -> IoErrorHandler
& {
572 return static_cast<IoErrorHandler
&>(x
.get());
577 ExternalFileUnit
*IoStatementState::GetExternalFileUnit() const {
578 return common::visit(
579 [](auto &x
) { return x
.get().GetExternalFileUnit(); }, u_
);
582 Fortran::common::optional
<char32_t
> IoStatementState::GetCurrentChar(
583 std::size_t &byteCount
) {
584 const char *p
{nullptr};
585 std::size_t bytes
{GetNextInputBytes(p
)};
588 return Fortran::common::nullopt
;
590 const ConnectionState
&connection
{GetConnectionState()};
591 if (connection
.isUTF8
) {
592 std::size_t length
{MeasureUTF8Bytes(*p
)};
593 if (length
<= bytes
) {
594 if (auto result
{DecodeUTF8(p
)}) {
599 GetIoErrorHandler().SignalError(IostatUTF8Decoding
);
600 // Error recovery: return the next byte
601 } else if (connection
.internalIoCharKind
> 1) {
602 byteCount
= connection
.internalIoCharKind
;
603 if (byteCount
== 2) {
604 return *reinterpret_cast<const char16_t
*>(p
);
606 return *reinterpret_cast<const char32_t
*>(p
);
614 Fortran::common::optional
<char32_t
> IoStatementState::NextInField(
615 Fortran::common::optional
<int> &remaining
, const DataEdit
&edit
) {
616 std::size_t byteCount
{0};
617 if (!remaining
) { // Stream, list-directed, or NAMELIST
618 if (auto next
{GetCurrentChar(byteCount
)}) {
619 if (edit
.IsListDirected()) {
620 // list-directed or NAMELIST: check for separators
630 case '\n': // for stream access
631 return Fortran::common::nullopt
;
634 if (edit
.IsNamelist()) {
635 return Fortran::common::nullopt
;
639 if (!(edit
.modes
.editingFlags
& decimalComma
)) {
640 return Fortran::common::nullopt
;
644 if (edit
.modes
.editingFlags
& decimalComma
) {
645 return Fortran::common::nullopt
;
652 HandleRelativePosition(byteCount
);
656 } else if (*remaining
> 0) {
657 if (auto next
{GetCurrentChar(byteCount
)}) {
658 if (byteCount
> static_cast<std::size_t>(*remaining
)) {
659 return Fortran::common::nullopt
;
661 *remaining
-= byteCount
;
662 HandleRelativePosition(byteCount
);
666 if (CheckForEndOfRecord(0)) { // do padding
668 return Fortran::common::optional
<char32_t
>{' '};
671 return Fortran::common::nullopt
;
674 bool IoStatementState::CheckForEndOfRecord(std::size_t afterReading
) {
675 const ConnectionState
&connection
{GetConnectionState()};
676 if (!connection
.IsAtEOF()) {
677 if (auto length
{connection
.EffectiveRecordLength()}) {
678 if (connection
.positionInRecord
+
679 static_cast<std::int64_t>(afterReading
) >=
681 IoErrorHandler
&handler
{GetIoErrorHandler()};
682 const auto &modes
{mutableModes()};
683 if (modes
.nonAdvancing
) {
684 if (connection
.access
== Access::Stream
&&
685 connection
.unterminatedRecord
) {
686 // Reading final unterminated record left by a
687 // non-advancing WRITE on a stream file prior to
688 // positioning or ENDFILE.
693 } else if (!modes
.pad
) {
694 handler
.SignalError(IostatRecordReadOverrun
);
696 return modes
.pad
; // PAD='YES'
703 bool IoStatementState::Inquire(
704 InquiryKeywordHash inquiry
, char *out
, std::size_t chars
) {
705 return common::visit(
706 [&](auto &x
) { return x
.get().Inquire(inquiry
, out
, chars
); }, u_
);
709 bool IoStatementState::Inquire(InquiryKeywordHash inquiry
, bool &out
) {
710 return common::visit(
711 [&](auto &x
) { return x
.get().Inquire(inquiry
, out
); }, u_
);
714 bool IoStatementState::Inquire(
715 InquiryKeywordHash inquiry
, std::int64_t id
, bool &out
) {
716 return common::visit(
717 [&](auto &x
) { return x
.get().Inquire(inquiry
, id
, out
); }, u_
);
720 bool IoStatementState::Inquire(InquiryKeywordHash inquiry
, std::int64_t &n
) {
721 return common::visit(
722 [&](auto &x
) { return x
.get().Inquire(inquiry
, n
); }, u_
);
725 std::int64_t IoStatementState::InquirePos() {
726 return common::visit([&](auto &x
) { return x
.get().InquirePos(); }, u_
);
729 void IoStatementState::GotChar(int n
) {
730 if (auto *formattedIn
{
731 get_if
<FormattedIoStatementState
<Direction::Input
>>()}) {
732 formattedIn
->GotChar(n
);
734 GetIoErrorHandler().Crash("IoStatementState::GotChar() called for "
735 "statement that is not formatted input");
740 FormattedIoStatementState
<Direction::Input
>::GetEditDescriptorChars() const {
744 void FormattedIoStatementState
<Direction::Input
>::GotChar(int n
) {
748 bool ListDirectedStatementState
<Direction::Output
>::EmitLeadingSpaceOrAdvance(
749 IoStatementState
&io
, std::size_t length
, bool isCharacter
) {
750 const ConnectionState
&connection
{io
.GetConnectionState()};
751 int space
{connection
.positionInRecord
== 0 ||
752 !(isCharacter
&& lastWasUndelimitedCharacter())};
753 set_lastWasUndelimitedCharacter(false);
754 if (connection
.NeedAdvance(space
+ length
)) {
755 return io
.AdvanceRecord();
758 return EmitAscii(io
, " ", 1);
763 Fortran::common::optional
<DataEdit
>
764 ListDirectedStatementState
<Direction::Output
>::GetNextDataEdit(
765 IoStatementState
&io
, int maxRepeat
) {
767 edit
.descriptor
= DataEdit::ListDirected
;
768 edit
.repeat
= maxRepeat
;
769 edit
.modes
= io
.mutableModes();
773 int ListDirectedStatementState
<Direction::Input
>::EndIoStatement() {
774 if (repeatPosition_
) {
775 repeatPosition_
->Cancel();
780 Fortran::common::optional
<DataEdit
>
781 ListDirectedStatementState
<Direction::Input
>::GetNextDataEdit(
782 IoStatementState
&io
, int maxRepeat
) {
783 // N.B. list-directed transfers cannot be nonadvancing (C1221)
784 ConnectionState
&connection
{io
.GetConnectionState()};
786 edit
.descriptor
= DataEdit::ListDirected
;
787 edit
.repeat
= 1; // may be overridden below
788 edit
.modes
= io
.mutableModes();
789 if (hitSlash_
) { // everything after '/' is nullified
790 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
794 if (edit
.modes
.editingFlags
& decimalComma
) {
797 std::size_t byteCount
{0};
798 if (remaining_
> 0 && !realPart_
) { // "r*c" repetition in progress
799 RUNTIME_CHECK(io
.GetIoErrorHandler(), repeatPosition_
.has_value());
800 repeatPosition_
.reset(); // restores the saved position
801 if (!imaginaryPart_
) {
802 edit
.repeat
= std::min
<int>(remaining_
, maxRepeat
);
803 auto ch
{io
.GetCurrentChar(byteCount
)};
804 if (!ch
|| *ch
== ' ' || *ch
== '\t' || *ch
== comma
) {
805 // "r*" repeated null
806 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
809 remaining_
-= edit
.repeat
;
810 if (remaining_
> 0) {
811 repeatPosition_
.emplace(io
);
813 if (!imaginaryPart_
) {
817 // Skip separators, handle a "r*c" repeat count; see 13.10.2 in Fortran 2018
818 if (imaginaryPart_
) {
819 imaginaryPart_
= false;
820 } else if (realPart_
) {
822 imaginaryPart_
= true;
823 edit
.descriptor
= DataEdit::ListDirectedImaginaryPart
;
825 auto ch
{io
.GetNextNonBlank(byteCount
)};
826 if (ch
&& *ch
== comma
&& eatComma_
) {
827 // Consume comma & whitespace after previous item.
828 // This includes the comma between real and imaginary components
829 // in list-directed/NAMELIST complex input.
830 // (When DECIMAL='COMMA', the comma is actually a semicolon.)
831 io
.HandleRelativePosition(byteCount
);
832 ch
= io
.GetNextNonBlank(byteCount
);
836 return Fortran::common::nullopt
;
840 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
843 if (*ch
== comma
) { // separator: null value
844 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
847 if (imaginaryPart_
) { // can't repeat components
850 if (*ch
>= '0' && *ch
<= '9') { // look for "r*" repetition count
851 auto start
{connection
.positionInRecord
};
854 static auto constexpr clamp
{(std::numeric_limits
<int>::max() - '9') / 10};
859 r
= 10 * r
+ (*ch
- '0');
860 io
.HandleRelativePosition(byteCount
);
861 ch
= io
.GetCurrentChar(byteCount
);
862 } while (ch
&& *ch
>= '0' && *ch
<= '9');
863 if (r
> 0 && ch
&& *ch
== '*') { // subtle: r must be nonzero
864 io
.HandleRelativePosition(byteCount
);
865 ch
= io
.GetCurrentChar(byteCount
);
866 if (ch
&& *ch
== '/') { // r*/
868 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
871 if (!ch
|| *ch
== ' ' || *ch
== '\t' || *ch
== comma
) { // "r*" null
872 edit
.descriptor
= DataEdit::ListDirectedNullValue
;
874 edit
.repeat
= std::min
<int>(r
, maxRepeat
);
875 remaining_
= r
- edit
.repeat
;
876 if (remaining_
> 0) {
877 repeatPosition_
.emplace(io
);
879 } else { // not a repetition count, just an integer value; rewind
880 connection
.positionInRecord
= start
;
883 if (!imaginaryPart_
&& ch
&& *ch
== '(') {
885 io
.HandleRelativePosition(byteCount
);
886 edit
.descriptor
= DataEdit::ListDirectedRealPart
;
891 template <Direction
DIR>
892 int ExternalListIoStatementState
<DIR>::EndIoStatement() {
893 if constexpr (DIR == Direction::Input
) {
894 if (auto status
{ListDirectedStatementState
<DIR>::EndIoStatement()};
895 status
!= IostatOk
) {
899 return ExternalIoStatementState
<DIR>::EndIoStatement();
902 template <Direction
DIR>
903 bool ExternalUnformattedIoStatementState
<DIR>::Receive(
904 char *data
, std::size_t bytes
, std::size_t elementBytes
) {
905 if constexpr (DIR == Direction::Output
) {
906 this->Crash("ExternalUnformattedIoStatementState::Receive() called for "
909 return this->unit().Receive(data
, bytes
, elementBytes
, *this);
912 template <Direction
DIR>
913 ChildIoStatementState
<DIR>::ChildIoStatementState(
914 ChildIo
&child
, const char *sourceFile
, int sourceLine
)
915 : IoStatementBase
{sourceFile
, sourceLine
}, child_
{child
} {}
917 template <Direction
DIR>
918 MutableModes
&ChildIoStatementState
<DIR>::mutableModes() {
919 #if !defined(RT_DEVICE_AVOID_RECURSION)
920 return child_
.parent().mutableModes();
922 ReportUnsupportedChildIo();
926 template <Direction
DIR>
927 ConnectionState
&ChildIoStatementState
<DIR>::GetConnectionState() {
928 #if !defined(RT_DEVICE_AVOID_RECURSION)
929 return child_
.parent().GetConnectionState();
931 ReportUnsupportedChildIo();
935 template <Direction
DIR>
936 ExternalFileUnit
*ChildIoStatementState
<DIR>::GetExternalFileUnit() const {
937 #if !defined(RT_DEVICE_AVOID_RECURSION)
938 return child_
.parent().GetExternalFileUnit();
940 ReportUnsupportedChildIo();
944 template <Direction
DIR> int ChildIoStatementState
<DIR>::EndIoStatement() {
946 auto result
{IoStatementBase::EndIoStatement()};
947 child_
.EndIoStatement(); // annihilates *this in child_.u_
951 template <Direction
DIR>
952 bool ChildIoStatementState
<DIR>::Emit(
953 const char *data
, std::size_t bytes
, std::size_t elementBytes
) {
954 #if !defined(RT_DEVICE_AVOID_RECURSION)
955 return child_
.parent().Emit(data
, bytes
, elementBytes
);
957 ReportUnsupportedChildIo();
961 template <Direction
DIR>
962 std::size_t ChildIoStatementState
<DIR>::GetNextInputBytes(const char *&p
) {
963 #if !defined(RT_DEVICE_AVOID_RECURSION)
964 return child_
.parent().GetNextInputBytes(p
);
966 ReportUnsupportedChildIo();
970 template <Direction
DIR>
971 void ChildIoStatementState
<DIR>::HandleAbsolutePosition(std::int64_t n
) {
972 #if !defined(RT_DEVICE_AVOID_RECURSION)
973 return child_
.parent().HandleAbsolutePosition(n
);
975 ReportUnsupportedChildIo();
979 template <Direction
DIR>
980 void ChildIoStatementState
<DIR>::HandleRelativePosition(std::int64_t n
) {
981 #if !defined(RT_DEVICE_AVOID_RECURSION)
982 return child_
.parent().HandleRelativePosition(n
);
984 ReportUnsupportedChildIo();
988 template <Direction
DIR, typename CHAR
>
989 ChildFormattedIoStatementState
<DIR, CHAR
>::ChildFormattedIoStatementState(
990 ChildIo
&child
, const CHAR
*format
, std::size_t formatLength
,
991 const Descriptor
*formatDescriptor
, const char *sourceFile
, int sourceLine
)
992 : ChildIoStatementState
<DIR>{child
, sourceFile
, sourceLine
},
993 mutableModes_
{child
.parent().mutableModes()}, format_
{*this, format
,
997 template <Direction
DIR, typename CHAR
>
998 void ChildFormattedIoStatementState
<DIR, CHAR
>::CompleteOperation() {
999 if (!this->completedOperation()) {
1000 format_
.Finish(*this);
1001 ChildIoStatementState
<DIR>::CompleteOperation();
1005 template <Direction
DIR, typename CHAR
>
1006 int ChildFormattedIoStatementState
<DIR, CHAR
>::EndIoStatement() {
1007 CompleteOperation();
1008 return ChildIoStatementState
<DIR>::EndIoStatement();
1011 template <Direction
DIR, typename CHAR
>
1012 bool ChildFormattedIoStatementState
<DIR, CHAR
>::AdvanceRecord(int n
) {
1013 #if !defined(RT_DEVICE_AVOID_RECURSION)
1014 return this->child().parent().AdvanceRecord(n
);
1016 this->ReportUnsupportedChildIo();
1020 template <Direction
DIR>
1021 bool ChildUnformattedIoStatementState
<DIR>::Receive(
1022 char *data
, std::size_t bytes
, std::size_t elementBytes
) {
1023 #if !defined(RT_DEVICE_AVOID_RECURSION)
1024 return this->child().parent().Receive(data
, bytes
, elementBytes
);
1026 this->ReportUnsupportedChildIo();
1030 template <Direction
DIR> int ChildListIoStatementState
<DIR>::EndIoStatement() {
1031 if constexpr (DIR == Direction::Input
) {
1032 if (int status
{ListDirectedStatementState
<DIR>::EndIoStatement()};
1033 status
!= IostatOk
) {
1037 return ChildIoStatementState
<DIR>::EndIoStatement();
1040 template class InternalIoStatementState
<Direction::Output
>;
1041 template class InternalIoStatementState
<Direction::Input
>;
1042 template class InternalFormattedIoStatementState
<Direction::Output
>;
1043 template class InternalFormattedIoStatementState
<Direction::Input
>;
1044 template class InternalListIoStatementState
<Direction::Output
>;
1045 template class InternalListIoStatementState
<Direction::Input
>;
1046 template class ExternalIoStatementState
<Direction::Output
>;
1047 template class ExternalIoStatementState
<Direction::Input
>;
1048 template class ExternalFormattedIoStatementState
<Direction::Output
>;
1049 template class ExternalFormattedIoStatementState
<Direction::Input
>;
1050 template class ExternalListIoStatementState
<Direction::Output
>;
1051 template class ExternalListIoStatementState
<Direction::Input
>;
1052 template class ExternalUnformattedIoStatementState
<Direction::Output
>;
1053 template class ExternalUnformattedIoStatementState
<Direction::Input
>;
1054 template class ChildIoStatementState
<Direction::Output
>;
1055 template class ChildIoStatementState
<Direction::Input
>;
1056 template class ChildFormattedIoStatementState
<Direction::Output
>;
1057 template class ChildFormattedIoStatementState
<Direction::Input
>;
1058 template class ChildListIoStatementState
<Direction::Output
>;
1059 template class ChildListIoStatementState
<Direction::Input
>;
1060 template class ChildUnformattedIoStatementState
<Direction::Output
>;
1061 template class ChildUnformattedIoStatementState
<Direction::Input
>;
1063 void ExternalMiscIoStatementState::CompleteOperation() {
1064 if (completedOperation()) {
1067 ExternalFileUnit
&ext
{unit()};
1070 ext
.FlushOutput(*this);
1071 #if !defined(RT_DEVICE_COMPILATION)
1072 std::fflush(nullptr); // flushes C stdio output streams (12.9(2))
1076 ext
.BackspaceRecord(*this);
1085 break; // handled in io-api.cpp BeginWait
1087 return IoStatementBase::CompleteOperation();
1090 int ExternalMiscIoStatementState::EndIoStatement() {
1091 CompleteOperation();
1092 return ExternalIoStatementBase::EndIoStatement();
1095 InquireUnitState::InquireUnitState(
1096 ExternalFileUnit
&unit
, const char *sourceFile
, int sourceLine
)
1097 : ExternalIoStatementBase
{unit
, sourceFile
, sourceLine
} {}
1099 bool InquireUnitState::Inquire(
1100 InquiryKeywordHash inquiry
, char *result
, std::size_t length
) {
1101 if (unit().createdForInternalChildIo()) {
1102 SignalError(IostatInquireInternalUnit
,
1103 "INQUIRE of unit created for defined derived type I/O of an internal "
1107 const char *str
{nullptr};
1109 case HashInquiryKeyword("ACCESS"):
1110 if (!unit().IsConnected()) {
1113 switch (unit().access
) {
1114 case Access::Sequential
:
1117 case Access::Direct
:
1120 case Access::Stream
:
1126 case HashInquiryKeyword("ACTION"):
1127 str
= !unit().IsConnected() ? "UNDEFINED"
1128 : unit().mayWrite() ? unit().mayRead() ? "READWRITE" : "WRITE"
1131 case HashInquiryKeyword("ASYNCHRONOUS"):
1132 str
= !unit().IsConnected() ? "UNDEFINED"
1133 : unit().mayAsynchronous() ? "YES"
1136 case HashInquiryKeyword("BLANK"):
1137 str
= !unit().IsConnected() || unit().isUnformatted
.value_or(true)
1139 : mutableModes().editingFlags
& blankZero
? "ZERO"
1142 case HashInquiryKeyword("CARRIAGECONTROL"):
1145 case HashInquiryKeyword("CONVERT"):
1146 str
= unit().swapEndianness() ? "SWAP" : "NATIVE";
1148 case HashInquiryKeyword("DECIMAL"):
1149 str
= !unit().IsConnected() || unit().isUnformatted
.value_or(true)
1151 : mutableModes().editingFlags
& decimalComma
? "COMMA"
1154 case HashInquiryKeyword("DELIM"):
1155 if (!unit().IsConnected() || unit().isUnformatted
.value_or(true)) {
1158 switch (mutableModes().delim
) {
1171 case HashInquiryKeyword("DIRECT"):
1172 str
= !unit().IsConnected() ? "UNKNOWN"
1173 : unit().access
== Access::Direct
||
1174 (unit().mayPosition() && unit().openRecl
)
1178 case HashInquiryKeyword("ENCODING"):
1179 str
= !unit().IsConnected() ? "UNKNOWN"
1180 : unit().isUnformatted
.value_or(true) ? "UNDEFINED"
1181 : unit().isUTF8
? "UTF-8"
1184 case HashInquiryKeyword("FORM"):
1185 str
= !unit().IsConnected() || !unit().isUnformatted
? "UNDEFINED"
1186 : *unit().isUnformatted
? "UNFORMATTED"
1189 case HashInquiryKeyword("FORMATTED"):
1190 str
= !unit().IsConnected() ? "UNDEFINED"
1191 : !unit().isUnformatted
? "UNKNOWN"
1192 : *unit().isUnformatted
? "NO"
1195 case HashInquiryKeyword("NAME"):
1196 str
= unit().path();
1198 return true; // result is undefined
1201 case HashInquiryKeyword("PAD"):
1202 str
= !unit().IsConnected() || unit().isUnformatted
.value_or(true)
1204 : mutableModes().pad
? "YES"
1207 case HashInquiryKeyword("POSITION"):
1208 if (!unit().IsConnected() || unit().access
== Access::Direct
) {
1211 switch (unit().InquirePosition()) {
1212 case Position::Rewind
:
1215 case Position::Append
:
1218 case Position::AsIs
:
1224 case HashInquiryKeyword("READ"):
1225 str
= !unit().IsConnected() ? "UNDEFINED" : unit().mayRead() ? "YES" : "NO";
1227 case HashInquiryKeyword("READWRITE"):
1228 str
= !unit().IsConnected() ? "UNDEFINED"
1229 : unit().mayRead() && unit().mayWrite() ? "YES"
1232 case HashInquiryKeyword("ROUND"):
1233 if (!unit().IsConnected() || unit().isUnformatted
.value_or(true)) {
1236 switch (mutableModes().round
) {
1237 case decimal::FortranRounding::RoundNearest
:
1240 case decimal::FortranRounding::RoundUp
:
1243 case decimal::FortranRounding::RoundDown
:
1246 case decimal::FortranRounding::RoundToZero
:
1249 case decimal::FortranRounding::RoundCompatible
:
1255 case HashInquiryKeyword("SEQUENTIAL"):
1256 // "NO" for Direct, since Sequential would not work if
1257 // the unit were reopened without RECL=.
1258 str
= !unit().IsConnected() ? "UNKNOWN"
1259 : unit().access
== Access::Sequential
? "YES"
1262 case HashInquiryKeyword("SIGN"):
1263 str
= !unit().IsConnected() || unit().isUnformatted
.value_or(true)
1265 : mutableModes().editingFlags
& signPlus
? "PLUS"
1268 case HashInquiryKeyword("STREAM"):
1269 str
= !unit().IsConnected() ? "UNKNOWN"
1270 : unit().access
== Access::Stream
? "YES"
1273 case HashInquiryKeyword("UNFORMATTED"):
1274 str
= !unit().IsConnected() || !unit().isUnformatted
? "UNKNOWN"
1275 : *unit().isUnformatted
? "YES"
1278 case HashInquiryKeyword("WRITE"):
1279 str
= !unit().IsConnected() ? "UNKNOWN" : unit().mayWrite() ? "YES" : "NO";
1283 ToFortranDefaultCharacter(result
, length
, str
);
1286 BadInquiryKeywordHashCrash(inquiry
);
1291 bool InquireUnitState::Inquire(InquiryKeywordHash inquiry
, bool &result
) {
1293 case HashInquiryKeyword("EXIST"):
1296 case HashInquiryKeyword("NAMED"):
1297 result
= unit().path() != nullptr;
1299 case HashInquiryKeyword("OPENED"):
1300 result
= unit().IsConnected();
1302 case HashInquiryKeyword("PENDING"):
1303 result
= false; // asynchronous I/O is not implemented
1306 BadInquiryKeywordHashCrash(inquiry
);
1311 bool InquireUnitState::Inquire(
1312 InquiryKeywordHash inquiry
, std::int64_t, bool &result
) {
1314 case HashInquiryKeyword("PENDING"):
1315 result
= false; // asynchronous I/O is not implemented
1318 BadInquiryKeywordHashCrash(inquiry
);
1323 bool InquireUnitState::Inquire(
1324 InquiryKeywordHash inquiry
, std::int64_t &result
) {
1326 case HashInquiryKeyword("NEXTREC"):
1327 if (unit().access
== Access::Direct
) {
1328 result
= unit().currentRecordNumber
;
1331 case HashInquiryKeyword("NUMBER"):
1332 result
= unit().unitNumber();
1334 case HashInquiryKeyword("POS"):
1335 result
= unit().InquirePos();
1337 case HashInquiryKeyword("RECL"):
1338 if (!unit().IsConnected()) {
1340 } else if (unit().access
== Access::Stream
) {
1342 } else if (unit().openRecl
) {
1343 result
= *unit().openRecl
;
1345 result
= std::numeric_limits
<std::int32_t>::max();
1348 case HashInquiryKeyword("SIZE"):
1350 if (unit().IsConnected()) {
1351 unit().FlushOutput(*this);
1352 if (auto size
{unit().knownSize()}) {
1358 BadInquiryKeywordHashCrash(inquiry
);
1363 InquireNoUnitState::InquireNoUnitState(
1364 const char *sourceFile
, int sourceLine
, int badUnitNumber
)
1365 : NoUnitIoStatementState
{*this, sourceFile
, sourceLine
, badUnitNumber
} {}
1367 bool InquireNoUnitState::Inquire(
1368 InquiryKeywordHash inquiry
, char *result
, std::size_t length
) {
1370 case HashInquiryKeyword("ACCESS"):
1371 case HashInquiryKeyword("ACTION"):
1372 case HashInquiryKeyword("ASYNCHRONOUS"):
1373 case HashInquiryKeyword("BLANK"):
1374 case HashInquiryKeyword("CARRIAGECONTROL"):
1375 case HashInquiryKeyword("CONVERT"):
1376 case HashInquiryKeyword("DECIMAL"):
1377 case HashInquiryKeyword("DELIM"):
1378 case HashInquiryKeyword("FORM"):
1379 case HashInquiryKeyword("NAME"):
1380 case HashInquiryKeyword("PAD"):
1381 case HashInquiryKeyword("POSITION"):
1382 case HashInquiryKeyword("ROUND"):
1383 case HashInquiryKeyword("SIGN"):
1384 ToFortranDefaultCharacter(result
, length
, "UNDEFINED");
1386 case HashInquiryKeyword("DIRECT"):
1387 case HashInquiryKeyword("ENCODING"):
1388 case HashInquiryKeyword("FORMATTED"):
1389 case HashInquiryKeyword("READ"):
1390 case HashInquiryKeyword("READWRITE"):
1391 case HashInquiryKeyword("SEQUENTIAL"):
1392 case HashInquiryKeyword("STREAM"):
1393 case HashInquiryKeyword("WRITE"):
1394 case HashInquiryKeyword("UNFORMATTED"):
1395 ToFortranDefaultCharacter(result
, length
, "UNKNOWN");
1398 BadInquiryKeywordHashCrash(inquiry
);
1403 bool InquireNoUnitState::Inquire(InquiryKeywordHash inquiry
, bool &result
) {
1405 case HashInquiryKeyword("EXIST"):
1406 result
= badUnitNumber() >= 0;
1408 case HashInquiryKeyword("NAMED"):
1409 case HashInquiryKeyword("OPENED"):
1410 case HashInquiryKeyword("PENDING"):
1414 BadInquiryKeywordHashCrash(inquiry
);
1419 bool InquireNoUnitState::Inquire(
1420 InquiryKeywordHash inquiry
, std::int64_t, bool &result
) {
1422 case HashInquiryKeyword("PENDING"):
1426 BadInquiryKeywordHashCrash(inquiry
);
1431 bool InquireNoUnitState::Inquire(
1432 InquiryKeywordHash inquiry
, std::int64_t &result
) {
1434 case HashInquiryKeyword("NUMBER"):
1435 result
= badUnitNumber();
1437 case HashInquiryKeyword("NEXTREC"):
1438 case HashInquiryKeyword("POS"):
1439 case HashInquiryKeyword("RECL"):
1440 case HashInquiryKeyword("SIZE"):
1444 BadInquiryKeywordHashCrash(inquiry
);
1449 InquireUnconnectedFileState::InquireUnconnectedFileState(
1450 OwningPtr
<char> &&path
, const char *sourceFile
, int sourceLine
)
1451 : NoUnitIoStatementState
{*this, sourceFile
, sourceLine
}, path_
{std::move(
1454 bool InquireUnconnectedFileState::Inquire(
1455 InquiryKeywordHash inquiry
, char *result
, std::size_t length
) {
1456 const char *str
{nullptr};
1458 case HashInquiryKeyword("ACCESS"):
1459 case HashInquiryKeyword("ACTION"):
1460 case HashInquiryKeyword("ASYNCHRONOUS"):
1461 case HashInquiryKeyword("BLANK"):
1462 case HashInquiryKeyword("CARRIAGECONTROL"):
1463 case HashInquiryKeyword("CONVERT"):
1464 case HashInquiryKeyword("DECIMAL"):
1465 case HashInquiryKeyword("DELIM"):
1466 case HashInquiryKeyword("FORM"):
1467 case HashInquiryKeyword("PAD"):
1468 case HashInquiryKeyword("POSITION"):
1469 case HashInquiryKeyword("ROUND"):
1470 case HashInquiryKeyword("SIGN"):
1473 case HashInquiryKeyword("DIRECT"):
1474 case HashInquiryKeyword("ENCODING"):
1475 case HashInquiryKeyword("FORMATTED"):
1476 case HashInquiryKeyword("SEQUENTIAL"):
1477 case HashInquiryKeyword("STREAM"):
1478 case HashInquiryKeyword("UNFORMATTED"):
1481 case HashInquiryKeyword("READ"):
1483 IsExtant(path_
.get()) ? MayRead(path_
.get()) ? "YES" : "NO" : "UNKNOWN";
1485 case HashInquiryKeyword("READWRITE"):
1486 str
= IsExtant(path_
.get()) ? MayReadAndWrite(path_
.get()) ? "YES" : "NO"
1489 case HashInquiryKeyword("WRITE"):
1490 str
= IsExtant(path_
.get()) ? MayWrite(path_
.get()) ? "YES" : "NO"
1493 case HashInquiryKeyword("NAME"):
1496 return true; // result is undefined
1501 ToFortranDefaultCharacter(result
, length
, str
);
1504 BadInquiryKeywordHashCrash(inquiry
);
1509 bool InquireUnconnectedFileState::Inquire(
1510 InquiryKeywordHash inquiry
, bool &result
) {
1512 case HashInquiryKeyword("EXIST"):
1513 result
= IsExtant(path_
.get());
1515 case HashInquiryKeyword("NAMED"):
1518 case HashInquiryKeyword("OPENED"):
1521 case HashInquiryKeyword("PENDING"):
1525 BadInquiryKeywordHashCrash(inquiry
);
1530 bool InquireUnconnectedFileState::Inquire(
1531 InquiryKeywordHash inquiry
, std::int64_t, bool &result
) {
1533 case HashInquiryKeyword("PENDING"):
1537 BadInquiryKeywordHashCrash(inquiry
);
1542 bool InquireUnconnectedFileState::Inquire(
1543 InquiryKeywordHash inquiry
, std::int64_t &result
) {
1545 case HashInquiryKeyword("NEXTREC"):
1546 case HashInquiryKeyword("NUMBER"):
1547 case HashInquiryKeyword("POS"):
1548 case HashInquiryKeyword("RECL"):
1551 case HashInquiryKeyword("SIZE"):
1552 result
= SizeInBytes(path_
.get());
1555 BadInquiryKeywordHashCrash(inquiry
);
1560 InquireIOLengthState::InquireIOLengthState(
1561 const char *sourceFile
, int sourceLine
)
1562 : NoUnitIoStatementState
{*this, sourceFile
, sourceLine
} {}
1564 bool InquireIOLengthState::Emit(const char *, std::size_t bytes
, std::size_t) {
1569 int ErroneousIoStatementState::EndIoStatement() {
1570 SignalPendingError();
1572 unit_
->EndIoStatement();
1574 return IoStatementBase::EndIoStatement();
1577 RT_OFFLOAD_API_GROUP_END
1578 } // namespace Fortran::runtime::io