1 //===-- runtime/io-stmt.h ---------------------------------------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Representations of the state of an I/O statement in progress 10 11 #ifndef FORTRAN_RUNTIME_IO_STMT_H_ 12 #define FORTRAN_RUNTIME_IO_STMT_H_ 13 14 #include "connection.h" 15 #include "file.h" 16 #include "format.h" 17 #include "internal-unit.h" 18 #include "io-error.h" 19 #include "flang/Common/optional.h" 20 #include "flang/Common/reference-wrapper.h" 21 #include "flang/Common/visit.h" 22 #include "flang/Runtime/descriptor.h" 23 #include "flang/Runtime/io-api.h" 24 #include <flang/Common/variant.h> 25 #include <functional> 26 #include <type_traits> 27 28 namespace Fortran::runtime::io { 29 30 class ExternalFileUnit; 31 class ChildIo; 32 33 class OpenStatementState; 34 class InquireUnitState; 35 class InquireNoUnitState; 36 class InquireUnconnectedFileState; 37 class InquireIOLengthState; 38 class ExternalMiscIoStatementState; 39 class CloseStatementState; 40 class NoopStatementState; // CLOSE or FLUSH on unknown unit 41 class ErroneousIoStatementState; 42 43 template <Direction, typename CHAR = char> 44 class InternalFormattedIoStatementState; 45 template <Direction> class InternalListIoStatementState; 46 template <Direction, typename CHAR = char> 47 class ExternalFormattedIoStatementState; 48 template <Direction> class ExternalListIoStatementState; 49 template <Direction> class ExternalUnformattedIoStatementState; 50 template <Direction, typename CHAR = char> class ChildFormattedIoStatementState; 51 template <Direction> class ChildListIoStatementState; 52 template <Direction> class ChildUnformattedIoStatementState; 53 54 struct InputStatementState {}; 55 struct OutputStatementState {}; 56 template <Direction D> 57 using IoDirectionState = std::conditional_t<D == Direction::Input, 58 InputStatementState, OutputStatementState>; 59 60 // Common state for all kinds of formatted I/O 61 template <Direction D> class FormattedIoStatementState {}; 62 template <> class FormattedIoStatementState<Direction::Input> { 63 public: 64 RT_API_ATTRS std::size_t GetEditDescriptorChars() const; 65 RT_API_ATTRS void GotChar(int); 66 67 private: 68 // Account of characters read for edit descriptors (i.e., formatted I/O 69 // with a FORMAT, not list-directed or NAMELIST), not including padding. 70 std::size_t chars_{0}; // for READ(SIZE=) 71 }; 72 73 // The Cookie type in the I/O API is a pointer (for C) to this class. 74 class IoStatementState { 75 public: 76 template <typename A> explicit RT_API_ATTRS IoStatementState(A &x) : u_{x} {} 77 78 // These member functions each project themselves into the active alternative. 79 // They're used by per-data-item routines in the I/O API (e.g., OutputReal64) 80 // to interact with the state of the I/O statement in progress. 81 // This design avoids virtual member functions and function pointers, 82 // which may not have good support in some runtime environments. 83 84 // CompleteOperation() is the last opportunity to raise an I/O error. 85 // It is called by EndIoStatement(), but it can be invoked earlier to 86 // catch errors for (e.g.) GetIoMsg() and GetNewUnit(). If called 87 // more than once, it is a no-op. 88 RT_API_ATTRS void CompleteOperation(); 89 // Completes an I/O statement and reclaims storage. 90 RT_API_ATTRS int EndIoStatement(); 91 92 RT_API_ATTRS bool Emit( 93 const char *, std::size_t bytes, std::size_t elementBytes = 0); 94 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0); 95 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&); 96 RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const; 97 RT_API_ATTRS bool AdvanceRecord(int = 1); 98 RT_API_ATTRS void BackspaceRecord(); 99 RT_API_ATTRS void HandleRelativePosition(std::int64_t byteOffset); 100 RT_API_ATTRS void HandleAbsolutePosition( 101 std::int64_t byteOffset); // for r* in list I/O 102 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 103 int maxRepeat = 1); 104 RT_API_ATTRS ExternalFileUnit * 105 GetExternalFileUnit() const; // null if internal unit 106 RT_API_ATTRS bool BeginReadingRecord(); 107 RT_API_ATTRS void FinishReadingRecord(); 108 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t); 109 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &); 110 RT_API_ATTRS bool Inquire( 111 InquiryKeywordHash, std::int64_t, bool &); // PENDING= 112 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &); 113 RT_API_ATTRS std::int64_t InquirePos(); 114 RT_API_ATTRS void GotChar(signed int = 1); // for READ(SIZE=); can be <0 115 116 RT_API_ATTRS MutableModes &mutableModes(); 117 RT_API_ATTRS ConnectionState &GetConnectionState(); 118 RT_API_ATTRS IoErrorHandler &GetIoErrorHandler() const; 119 120 // N.B.: this also works with base classes 121 template <typename A> RT_API_ATTRS A *get_if() const { 122 return common::visit( 123 [](auto &x) -> A * { 124 if constexpr (std::is_convertible_v<decltype(x.get()), A &>) { 125 return &x.get(); 126 } 127 return nullptr; 128 }, 129 u_); 130 } 131 132 // Vacant after the end of the current record 133 RT_API_ATTRS Fortran::common::optional<char32_t> GetCurrentChar( 134 std::size_t &byteCount); 135 136 // The result of CueUpInput() and the "remaining" arguments to SkipSpaces() 137 // and NextInField() are always in units of bytes, not characters; the 138 // distinction matters for internal input from CHARACTER(KIND=2 and 4). 139 140 // For fixed-width fields, return the number of remaining bytes. 141 // Skip over leading blanks. 142 RT_API_ATTRS Fortran::common::optional<int> CueUpInput(const DataEdit &edit) { 143 Fortran::common::optional<int> remaining; 144 if (edit.IsListDirected()) { 145 std::size_t byteCount{0}; 146 GetNextNonBlank(byteCount); 147 } else { 148 if (edit.width.value_or(0) > 0) { 149 remaining = *edit.width; 150 if (int bytesPerChar{GetConnectionState().internalIoCharKind}; 151 bytesPerChar > 1) { 152 *remaining *= bytesPerChar; 153 } 154 } 155 SkipSpaces(remaining); 156 } 157 return remaining; 158 } 159 160 RT_API_ATTRS Fortran::common::optional<char32_t> SkipSpaces( 161 Fortran::common::optional<int> &remaining) { 162 while (!remaining || *remaining > 0) { 163 std::size_t byteCount{0}; 164 if (auto ch{GetCurrentChar(byteCount)}) { 165 if (*ch != ' ' && *ch != '\t') { 166 return ch; 167 } 168 if (remaining) { 169 if (static_cast<std::size_t>(*remaining) < byteCount) { 170 break; 171 } 172 GotChar(byteCount); 173 *remaining -= byteCount; 174 } 175 HandleRelativePosition(byteCount); 176 } else { 177 break; 178 } 179 } 180 return Fortran::common::nullopt; 181 } 182 183 // Acquires the next input character, respecting any applicable field width 184 // or separator character. 185 RT_API_ATTRS Fortran::common::optional<char32_t> NextInField( 186 Fortran::common::optional<int> &remaining, const DataEdit &); 187 188 // Detect and signal any end-of-record condition after input. 189 // Returns true if at EOR and remaining input should be padded with blanks. 190 RT_API_ATTRS bool CheckForEndOfRecord(std::size_t afterReading); 191 192 // Skips spaces, advances records, and ignores NAMELIST comments 193 RT_API_ATTRS Fortran::common::optional<char32_t> GetNextNonBlank( 194 std::size_t &byteCount) { 195 auto ch{GetCurrentChar(byteCount)}; 196 bool inNamelist{mutableModes().inNamelist}; 197 while (!ch || *ch == ' ' || *ch == '\t' || *ch == '\n' || 198 (inNamelist && *ch == '!')) { 199 if (ch && (*ch == ' ' || *ch == '\t' || *ch == '\n')) { 200 HandleRelativePosition(byteCount); 201 } else if (!AdvanceRecord()) { 202 return Fortran::common::nullopt; 203 } 204 ch = GetCurrentChar(byteCount); 205 } 206 return ch; 207 } 208 209 template <Direction D> 210 RT_API_ATTRS bool CheckFormattedStmtType(const char *name) { 211 if (get_if<FormattedIoStatementState<D>>()) { 212 return true; 213 } else { 214 auto &handler{GetIoErrorHandler()}; 215 if (!handler.InError()) { 216 handler.Crash("%s called for I/O statement that is not formatted %s", 217 name, D == Direction::Output ? "output" : "input"); 218 } 219 return false; 220 } 221 } 222 223 private: 224 std::variant<Fortran::common::reference_wrapper<OpenStatementState>, 225 Fortran::common::reference_wrapper<CloseStatementState>, 226 Fortran::common::reference_wrapper<NoopStatementState>, 227 Fortran::common::reference_wrapper< 228 InternalFormattedIoStatementState<Direction::Output>>, 229 Fortran::common::reference_wrapper< 230 InternalFormattedIoStatementState<Direction::Input>>, 231 Fortran::common::reference_wrapper< 232 InternalListIoStatementState<Direction::Output>>, 233 Fortran::common::reference_wrapper< 234 InternalListIoStatementState<Direction::Input>>, 235 Fortran::common::reference_wrapper< 236 ExternalFormattedIoStatementState<Direction::Output>>, 237 Fortran::common::reference_wrapper< 238 ExternalFormattedIoStatementState<Direction::Input>>, 239 Fortran::common::reference_wrapper< 240 ExternalListIoStatementState<Direction::Output>>, 241 Fortran::common::reference_wrapper< 242 ExternalListIoStatementState<Direction::Input>>, 243 Fortran::common::reference_wrapper< 244 ExternalUnformattedIoStatementState<Direction::Output>>, 245 Fortran::common::reference_wrapper< 246 ExternalUnformattedIoStatementState<Direction::Input>>, 247 Fortran::common::reference_wrapper< 248 ChildFormattedIoStatementState<Direction::Output>>, 249 Fortran::common::reference_wrapper< 250 ChildFormattedIoStatementState<Direction::Input>>, 251 Fortran::common::reference_wrapper< 252 ChildListIoStatementState<Direction::Output>>, 253 Fortran::common::reference_wrapper< 254 ChildListIoStatementState<Direction::Input>>, 255 Fortran::common::reference_wrapper< 256 ChildUnformattedIoStatementState<Direction::Output>>, 257 Fortran::common::reference_wrapper< 258 ChildUnformattedIoStatementState<Direction::Input>>, 259 Fortran::common::reference_wrapper<InquireUnitState>, 260 Fortran::common::reference_wrapper<InquireNoUnitState>, 261 Fortran::common::reference_wrapper<InquireUnconnectedFileState>, 262 Fortran::common::reference_wrapper<InquireIOLengthState>, 263 Fortran::common::reference_wrapper<ExternalMiscIoStatementState>, 264 Fortran::common::reference_wrapper<ErroneousIoStatementState>> 265 u_; 266 }; 267 268 // Base class for all per-I/O statement state classes. 269 class IoStatementBase : public IoErrorHandler { 270 public: 271 using IoErrorHandler::IoErrorHandler; 272 273 RT_API_ATTRS bool completedOperation() const { return completedOperation_; } 274 275 RT_API_ATTRS void CompleteOperation() { completedOperation_ = true; } 276 RT_API_ATTRS int EndIoStatement() { return GetIoStat(); } 277 278 // These are default no-op backstops that can be overridden by descendants. 279 RT_API_ATTRS bool Emit( 280 const char *, std::size_t bytes, std::size_t elementBytes = 0); 281 RT_API_ATTRS bool Receive( 282 char *, std::size_t bytes, std::size_t elementBytes = 0); 283 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&); 284 RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const; 285 RT_API_ATTRS bool AdvanceRecord(int); 286 RT_API_ATTRS void BackspaceRecord(); 287 RT_API_ATTRS void HandleRelativePosition(std::int64_t); 288 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t); 289 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 290 IoStatementState &, int maxRepeat = 1); 291 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const; 292 RT_API_ATTRS bool BeginReadingRecord(); 293 RT_API_ATTRS void FinishReadingRecord(); 294 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t); 295 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &); 296 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &); 297 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &); 298 RT_API_ATTRS std::int64_t InquirePos(); 299 300 RT_API_ATTRS void BadInquiryKeywordHashCrash(InquiryKeywordHash); 301 302 RT_API_ATTRS void ReportUnsupportedChildIo() const { 303 Crash("not yet implemented: child IO"); 304 } 305 306 protected: 307 bool completedOperation_{false}; 308 }; 309 310 // Common state for list-directed & NAMELIST I/O, both internal & external 311 template <Direction> class ListDirectedStatementState; 312 template <> 313 class ListDirectedStatementState<Direction::Output> 314 : public FormattedIoStatementState<Direction::Output> { 315 public: 316 RT_API_ATTRS bool EmitLeadingSpaceOrAdvance( 317 IoStatementState &, std::size_t = 1, bool isCharacter = false); 318 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 319 IoStatementState &, int maxRepeat = 1); 320 RT_API_ATTRS bool lastWasUndelimitedCharacter() const { 321 return lastWasUndelimitedCharacter_; 322 } 323 RT_API_ATTRS void set_lastWasUndelimitedCharacter(bool yes = true) { 324 lastWasUndelimitedCharacter_ = yes; 325 } 326 327 private: 328 bool lastWasUndelimitedCharacter_{false}; 329 }; 330 template <> 331 class ListDirectedStatementState<Direction::Input> 332 : public FormattedIoStatementState<Direction::Input> { 333 public: 334 RT_API_ATTRS bool inNamelistSequence() const { return inNamelistSequence_; } 335 RT_API_ATTRS int EndIoStatement(); 336 337 // Skips value separators, handles repetition and null values. 338 // Vacant when '/' appears; present with descriptor == ListDirectedNullValue 339 // when a null value appears. 340 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 341 IoStatementState &, int maxRepeat = 1); 342 343 // Each NAMELIST input item is treated like a distinct list-directed 344 // input statement. This member function resets some state so that 345 // repetition and null values work correctly for each successive 346 // NAMELIST input item. 347 RT_API_ATTRS void ResetForNextNamelistItem(bool inNamelistSequence) { 348 remaining_ = 0; 349 if (repeatPosition_) { 350 repeatPosition_->Cancel(); 351 } 352 eatComma_ = false; 353 realPart_ = imaginaryPart_ = false; 354 inNamelistSequence_ = inNamelistSequence; 355 } 356 357 private: 358 int remaining_{0}; // for "r*" repetition 359 Fortran::common::optional<SavedPosition> repeatPosition_; 360 bool eatComma_{false}; // consume comma after previously read item 361 bool hitSlash_{false}; // once '/' is seen, nullify further items 362 bool realPart_{false}; 363 bool imaginaryPart_{false}; 364 bool inNamelistSequence_{false}; 365 }; 366 367 template <Direction DIR> 368 class InternalIoStatementState : public IoStatementBase, 369 public IoDirectionState<DIR> { 370 public: 371 using Buffer = 372 std::conditional_t<DIR == Direction::Input, const char *, char *>; 373 RT_API_ATTRS InternalIoStatementState(Buffer, std::size_t, 374 const char *sourceFile = nullptr, int sourceLine = 0); 375 RT_API_ATTRS InternalIoStatementState( 376 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0); 377 RT_API_ATTRS int EndIoStatement(); 378 379 RT_API_ATTRS bool Emit( 380 const char *data, std::size_t bytes, std::size_t elementBytes = 0); 381 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&); 382 RT_API_ATTRS bool AdvanceRecord(int = 1); 383 RT_API_ATTRS void BackspaceRecord(); 384 RT_API_ATTRS ConnectionState &GetConnectionState() { return unit_; } 385 RT_API_ATTRS MutableModes &mutableModes() { return unit_.modes; } 386 RT_API_ATTRS void HandleRelativePosition(std::int64_t); 387 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t); 388 RT_API_ATTRS std::int64_t InquirePos(); 389 390 protected: 391 bool free_{true}; 392 InternalDescriptorUnit<DIR> unit_; 393 }; 394 395 template <Direction DIR, typename CHAR> 396 class InternalFormattedIoStatementState 397 : public InternalIoStatementState<DIR>, 398 public FormattedIoStatementState<DIR> { 399 public: 400 using CharType = CHAR; 401 using typename InternalIoStatementState<DIR>::Buffer; 402 RT_API_ATTRS InternalFormattedIoStatementState(Buffer internal, 403 std::size_t internalLength, const CharType *format, 404 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr, 405 const char *sourceFile = nullptr, int sourceLine = 0); 406 RT_API_ATTRS InternalFormattedIoStatementState(const Descriptor &, 407 const CharType *format, std::size_t formatLength, 408 const Descriptor *formatDescriptor = nullptr, 409 const char *sourceFile = nullptr, int sourceLine = 0); 410 RT_API_ATTRS IoStatementState &ioStatementState() { 411 return ioStatementState_; 412 } 413 RT_API_ATTRS void CompleteOperation(); 414 RT_API_ATTRS int EndIoStatement(); 415 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 416 IoStatementState &, int maxRepeat = 1) { 417 return format_.GetNextDataEdit(*this, maxRepeat); 418 } 419 420 private: 421 IoStatementState ioStatementState_; // points to *this 422 using InternalIoStatementState<DIR>::unit_; 423 // format_ *must* be last; it may be partial someday 424 FormatControl<InternalFormattedIoStatementState> format_; 425 }; 426 427 template <Direction DIR> 428 class InternalListIoStatementState : public InternalIoStatementState<DIR>, 429 public ListDirectedStatementState<DIR> { 430 public: 431 using typename InternalIoStatementState<DIR>::Buffer; 432 RT_API_ATTRS InternalListIoStatementState(Buffer internal, 433 std::size_t internalLength, const char *sourceFile = nullptr, 434 int sourceLine = 0); 435 RT_API_ATTRS InternalListIoStatementState( 436 const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0); 437 RT_API_ATTRS IoStatementState &ioStatementState() { 438 return ioStatementState_; 439 } 440 using ListDirectedStatementState<DIR>::GetNextDataEdit; 441 RT_API_ATTRS void CompleteOperation(); 442 RT_API_ATTRS int EndIoStatement(); 443 444 private: 445 IoStatementState ioStatementState_; // points to *this 446 using InternalIoStatementState<DIR>::unit_; 447 }; 448 449 class ExternalIoStatementBase : public IoStatementBase { 450 public: 451 RT_API_ATTRS ExternalIoStatementBase( 452 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0); 453 RT_API_ATTRS ExternalFileUnit &unit() { return unit_; } 454 RT_API_ATTRS const ExternalFileUnit &unit() const { return unit_; } 455 RT_API_ATTRS MutableModes &mutableModes(); 456 RT_API_ATTRS ConnectionState &GetConnectionState(); 457 RT_API_ATTRS int asynchronousID() const { return asynchronousID_; } 458 RT_API_ATTRS void set_destroy(bool yes = true) { destroy_ = yes; } 459 RT_API_ATTRS int EndIoStatement(); 460 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const { return &unit_; } 461 RT_API_ATTRS void SetAsynchronous(); 462 RT_API_ATTRS std::int64_t InquirePos(); 463 464 private: 465 ExternalFileUnit &unit_; 466 int asynchronousID_{-1}; 467 bool destroy_{false}; 468 }; 469 470 template <Direction DIR> 471 class ExternalIoStatementState : public ExternalIoStatementBase, 472 public IoDirectionState<DIR> { 473 public: 474 RT_API_ATTRS ExternalIoStatementState( 475 ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0); 476 RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; } 477 RT_API_ATTRS void CompleteOperation(); 478 RT_API_ATTRS int EndIoStatement(); 479 RT_API_ATTRS bool Emit( 480 const char *, std::size_t bytes, std::size_t elementBytes = 0); 481 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&); 482 RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const; 483 RT_API_ATTRS bool AdvanceRecord(int = 1); 484 RT_API_ATTRS void BackspaceRecord(); 485 RT_API_ATTRS void HandleRelativePosition(std::int64_t); 486 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t); 487 RT_API_ATTRS bool BeginReadingRecord(); 488 RT_API_ATTRS void FinishReadingRecord(); 489 490 private: 491 // These are forked from ConnectionState's modes at the beginning 492 // of each formatted I/O statement so they may be overridden by control 493 // edit descriptors during the statement. 494 MutableModes mutableModes_; 495 }; 496 497 template <Direction DIR, typename CHAR> 498 class ExternalFormattedIoStatementState 499 : public ExternalIoStatementState<DIR>, 500 public FormattedIoStatementState<DIR> { 501 public: 502 using CharType = CHAR; 503 RT_API_ATTRS ExternalFormattedIoStatementState(ExternalFileUnit &, 504 const CharType *format, std::size_t formatLength, 505 const Descriptor *formatDescriptor = nullptr, 506 const char *sourceFile = nullptr, int sourceLine = 0); 507 RT_API_ATTRS void CompleteOperation(); 508 RT_API_ATTRS int EndIoStatement(); 509 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 510 IoStatementState &, int maxRepeat = 1) { 511 return format_.GetNextDataEdit(*this, maxRepeat); 512 } 513 514 private: 515 FormatControl<ExternalFormattedIoStatementState> format_; 516 }; 517 518 template <Direction DIR> 519 class ExternalListIoStatementState : public ExternalIoStatementState<DIR>, 520 public ListDirectedStatementState<DIR> { 521 public: 522 using ExternalIoStatementState<DIR>::ExternalIoStatementState; 523 using ListDirectedStatementState<DIR>::GetNextDataEdit; 524 RT_API_ATTRS int EndIoStatement(); 525 }; 526 527 template <Direction DIR> 528 class ExternalUnformattedIoStatementState 529 : public ExternalIoStatementState<DIR> { 530 public: 531 using ExternalIoStatementState<DIR>::ExternalIoStatementState; 532 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0); 533 }; 534 535 template <Direction DIR> 536 class ChildIoStatementState : public IoStatementBase, 537 public IoDirectionState<DIR> { 538 public: 539 RT_API_ATTRS ChildIoStatementState( 540 ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0); 541 RT_API_ATTRS ChildIo &child() { return child_; } 542 RT_API_ATTRS MutableModes &mutableModes(); 543 RT_API_ATTRS ConnectionState &GetConnectionState(); 544 RT_API_ATTRS ExternalFileUnit *GetExternalFileUnit() const; 545 RT_API_ATTRS int EndIoStatement(); 546 RT_API_ATTRS bool Emit( 547 const char *, std::size_t bytes, std::size_t elementBytes = 0); 548 RT_API_ATTRS std::size_t GetNextInputBytes(const char *&); 549 RT_API_ATTRS std::size_t ViewBytesInRecord(const char *&, bool forward) const; 550 RT_API_ATTRS void HandleRelativePosition(std::int64_t); 551 RT_API_ATTRS void HandleAbsolutePosition(std::int64_t); 552 553 private: 554 ChildIo &child_; 555 }; 556 557 template <Direction DIR, typename CHAR> 558 class ChildFormattedIoStatementState : public ChildIoStatementState<DIR>, 559 public FormattedIoStatementState<DIR> { 560 public: 561 using CharType = CHAR; 562 RT_API_ATTRS ChildFormattedIoStatementState(ChildIo &, const CharType *format, 563 std::size_t formatLength, const Descriptor *formatDescriptor = nullptr, 564 const char *sourceFile = nullptr, int sourceLine = 0); 565 RT_API_ATTRS MutableModes &mutableModes() { return mutableModes_; } 566 RT_API_ATTRS void CompleteOperation(); 567 RT_API_ATTRS int EndIoStatement(); 568 RT_API_ATTRS bool AdvanceRecord(int = 1); 569 RT_API_ATTRS Fortran::common::optional<DataEdit> GetNextDataEdit( 570 IoStatementState &, int maxRepeat = 1) { 571 return format_.GetNextDataEdit(*this, maxRepeat); 572 } 573 574 private: 575 MutableModes mutableModes_; 576 FormatControl<ChildFormattedIoStatementState> format_; 577 }; 578 579 template <Direction DIR> 580 class ChildListIoStatementState : public ChildIoStatementState<DIR>, 581 public ListDirectedStatementState<DIR> { 582 public: 583 using ChildIoStatementState<DIR>::ChildIoStatementState; 584 using ListDirectedStatementState<DIR>::GetNextDataEdit; 585 RT_API_ATTRS int EndIoStatement(); 586 }; 587 588 template <Direction DIR> 589 class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> { 590 public: 591 using ChildIoStatementState<DIR>::ChildIoStatementState; 592 RT_API_ATTRS bool Receive(char *, std::size_t, std::size_t elementBytes = 0); 593 }; 594 595 // OPEN 596 class OpenStatementState : public ExternalIoStatementBase { 597 public: 598 RT_API_ATTRS OpenStatementState(ExternalFileUnit &unit, bool wasExtant, 599 bool isNewUnit, const char *sourceFile = nullptr, int sourceLine = 0) 600 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, 601 wasExtant_{wasExtant}, isNewUnit_{isNewUnit} {} 602 RT_API_ATTRS bool wasExtant() const { return wasExtant_; } 603 RT_API_ATTRS void set_status(OpenStatus status) { 604 status_ = status; 605 } // STATUS= 606 RT_API_ATTRS void set_path(const char *, std::size_t); // FILE= 607 RT_API_ATTRS void set_position(Position position) { 608 position_ = position; 609 } // POSITION= 610 RT_API_ATTRS void set_action(Action action) { action_ = action; } // ACTION= 611 RT_API_ATTRS void set_convert(Convert convert) { 612 convert_ = convert; 613 } // CONVERT= 614 RT_API_ATTRS void set_access(Access access) { access_ = access; } // ACCESS= 615 RT_API_ATTRS void set_isUnformatted(bool yes = true) { 616 isUnformatted_ = yes; 617 } // FORM= 618 619 RT_API_ATTRS void CompleteOperation(); 620 RT_API_ATTRS int EndIoStatement(); 621 622 private: 623 bool wasExtant_; 624 bool isNewUnit_; 625 Fortran::common::optional<OpenStatus> status_; 626 Fortran::common::optional<Position> position_; 627 Fortran::common::optional<Action> action_; 628 Convert convert_{Convert::Unknown}; 629 OwningPtr<char> path_; 630 std::size_t pathLength_; 631 Fortran::common::optional<bool> isUnformatted_; 632 Fortran::common::optional<Access> access_; 633 }; 634 635 class CloseStatementState : public ExternalIoStatementBase { 636 public: 637 RT_API_ATTRS CloseStatementState(ExternalFileUnit &unit, 638 const char *sourceFile = nullptr, int sourceLine = 0) 639 : ExternalIoStatementBase{unit, sourceFile, sourceLine} {} 640 RT_API_ATTRS void set_status(CloseStatus status) { status_ = status; } 641 RT_API_ATTRS int EndIoStatement(); 642 643 private: 644 CloseStatus status_{CloseStatus::Keep}; 645 }; 646 647 // For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit), 648 // and recoverable BACKSPACE(bad unit) 649 class NoUnitIoStatementState : public IoStatementBase { 650 public: 651 RT_API_ATTRS IoStatementState &ioStatementState() { 652 return ioStatementState_; 653 } 654 RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; } 655 RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; } 656 RT_API_ATTRS int badUnitNumber() const { return badUnitNumber_; } 657 RT_API_ATTRS void CompleteOperation(); 658 RT_API_ATTRS int EndIoStatement(); 659 660 protected: 661 template <typename A> 662 RT_API_ATTRS NoUnitIoStatementState(A &stmt, const char *sourceFile = nullptr, 663 int sourceLine = 0, int badUnitNumber = -1) 664 : IoStatementBase{sourceFile, sourceLine}, ioStatementState_{stmt}, 665 badUnitNumber_{badUnitNumber} {} 666 667 private: 668 IoStatementState ioStatementState_; // points to *this 669 ConnectionState connection_; 670 int badUnitNumber_; 671 }; 672 673 class NoopStatementState : public NoUnitIoStatementState { 674 public: 675 RT_API_ATTRS NoopStatementState( 676 const char *sourceFile = nullptr, int sourceLine = 0, int unitNumber = -1) 677 : NoUnitIoStatementState{*this, sourceFile, sourceLine, unitNumber} {} 678 RT_API_ATTRS void set_status(CloseStatus) {} // discards 679 }; 680 681 extern template class InternalIoStatementState<Direction::Output>; 682 extern template class InternalIoStatementState<Direction::Input>; 683 extern template class InternalFormattedIoStatementState<Direction::Output>; 684 extern template class InternalFormattedIoStatementState<Direction::Input>; 685 extern template class InternalListIoStatementState<Direction::Output>; 686 extern template class InternalListIoStatementState<Direction::Input>; 687 extern template class ExternalIoStatementState<Direction::Output>; 688 extern template class ExternalIoStatementState<Direction::Input>; 689 extern template class ExternalFormattedIoStatementState<Direction::Output>; 690 extern template class ExternalFormattedIoStatementState<Direction::Input>; 691 extern template class ExternalListIoStatementState<Direction::Output>; 692 extern template class ExternalListIoStatementState<Direction::Input>; 693 extern template class ExternalUnformattedIoStatementState<Direction::Output>; 694 extern template class ExternalUnformattedIoStatementState<Direction::Input>; 695 extern template class ChildIoStatementState<Direction::Output>; 696 extern template class ChildIoStatementState<Direction::Input>; 697 extern template class ChildFormattedIoStatementState<Direction::Output>; 698 extern template class ChildFormattedIoStatementState<Direction::Input>; 699 extern template class ChildListIoStatementState<Direction::Output>; 700 extern template class ChildListIoStatementState<Direction::Input>; 701 extern template class ChildUnformattedIoStatementState<Direction::Output>; 702 extern template class ChildUnformattedIoStatementState<Direction::Input>; 703 704 extern template class FormatControl< 705 InternalFormattedIoStatementState<Direction::Output>>; 706 extern template class FormatControl< 707 InternalFormattedIoStatementState<Direction::Input>>; 708 extern template class FormatControl< 709 ExternalFormattedIoStatementState<Direction::Output>>; 710 extern template class FormatControl< 711 ExternalFormattedIoStatementState<Direction::Input>>; 712 extern template class FormatControl< 713 ChildFormattedIoStatementState<Direction::Output>>; 714 extern template class FormatControl< 715 ChildFormattedIoStatementState<Direction::Input>>; 716 717 class InquireUnitState : public ExternalIoStatementBase { 718 public: 719 RT_API_ATTRS InquireUnitState(ExternalFileUnit &unit, 720 const char *sourceFile = nullptr, int sourceLine = 0); 721 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t); 722 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &); 723 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &); 724 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &); 725 }; 726 727 class InquireNoUnitState : public NoUnitIoStatementState { 728 public: 729 RT_API_ATTRS InquireNoUnitState(const char *sourceFile = nullptr, 730 int sourceLine = 0, int badUnitNumber = -1); 731 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t); 732 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &); 733 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &); 734 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &); 735 }; 736 737 class InquireUnconnectedFileState : public NoUnitIoStatementState { 738 public: 739 RT_API_ATTRS InquireUnconnectedFileState(OwningPtr<char> &&path, 740 const char *sourceFile = nullptr, int sourceLine = 0); 741 RT_API_ATTRS bool Inquire(InquiryKeywordHash, char *, std::size_t); 742 RT_API_ATTRS bool Inquire(InquiryKeywordHash, bool &); 743 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t, bool &); 744 RT_API_ATTRS bool Inquire(InquiryKeywordHash, std::int64_t &); 745 746 private: 747 OwningPtr<char> path_; // trimmed and NUL terminated 748 }; 749 750 class InquireIOLengthState : public NoUnitIoStatementState, 751 public OutputStatementState { 752 public: 753 RT_API_ATTRS InquireIOLengthState( 754 const char *sourceFile = nullptr, int sourceLine = 0); 755 RT_API_ATTRS std::size_t bytes() const { return bytes_; } 756 RT_API_ATTRS bool Emit( 757 const char *, std::size_t bytes, std::size_t elementBytes = 0); 758 759 private: 760 std::size_t bytes_{0}; 761 }; 762 763 class ExternalMiscIoStatementState : public ExternalIoStatementBase { 764 public: 765 enum Which { Flush, Backspace, Endfile, Rewind, Wait }; 766 RT_API_ATTRS ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which, 767 const char *sourceFile = nullptr, int sourceLine = 0) 768 : ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {} 769 RT_API_ATTRS void CompleteOperation(); 770 RT_API_ATTRS int EndIoStatement(); 771 772 private: 773 Which which_; 774 }; 775 776 class ErroneousIoStatementState : public IoStatementBase { 777 public: 778 explicit RT_API_ATTRS ErroneousIoStatementState(Iostat iostat, 779 ExternalFileUnit *unit = nullptr, const char *sourceFile = nullptr, 780 int sourceLine = 0) 781 : IoStatementBase{sourceFile, sourceLine}, unit_{unit} { 782 SetPendingError(iostat); 783 } 784 RT_API_ATTRS int EndIoStatement(); 785 RT_API_ATTRS ConnectionState &GetConnectionState() { return connection_; } 786 RT_API_ATTRS MutableModes &mutableModes() { return connection_.modes; } 787 788 private: 789 ConnectionState connection_; 790 ExternalFileUnit *unit_{nullptr}; 791 }; 792 793 } // namespace Fortran::runtime::io 794 #endif // FORTRAN_RUNTIME_IO_STMT_H_ 795