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