1313#include " tools.h"
1414#include " unit.h"
1515#include < algorithm>
16+ #include < cstdio>
1617#include < cstring>
1718#include < limits>
1819
@@ -182,10 +183,10 @@ int NoopCloseStatementState::EndIoStatement() {
182183}
183184
184185template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
186+ if (!unit ().nonAdvancing ) {
187+ unit ().AdvanceRecord (*this );
188+ }
185189 if constexpr (DIR == Direction::Output) {
186- if (!unit ().nonAdvancing ) {
187- unit ().AdvanceRecord (*this );
188- }
189190 unit ().FlushIfTerminal (*this );
190191 }
191192 return ExternalIoStatementBase::EndIoStatement ();
@@ -291,7 +292,7 @@ void IoStatementState::BackspaceRecord() {
291292}
292293
293294void IoStatementState::HandleRelativePosition (std::int64_t n) {
294- return std::visit ([=](auto &x) { x.get ().HandleRelativePosition (n); }, u_);
295+ std::visit ([=](auto &x) { x.get ().HandleRelativePosition (n); }, u_);
295296}
296297
297298int IoStatementState::EndIoStatement () {
@@ -347,15 +348,22 @@ bool IoStatementState::EmitField(
347348 }
348349}
349350
350- void IoStatementState::SkipSpaces (std::optional<int > &remaining) {
351- if (!remaining || *remaining > 0 ) {
352- for (auto ch{GetCurrentChar ()}; ch && ch == ' ' ; ch = GetCurrentChar ()) {
351+ std::optional<char32_t > IoStatementState::SkipSpaces (
352+ std::optional<int > &remaining) {
353+ while (!remaining || *remaining > 0 ) {
354+ if (auto ch{GetCurrentChar ()}) {
355+ if (*ch != ' ' ) {
356+ return ch;
357+ }
353358 HandleRelativePosition (1 );
354- if (remaining && !--*remaining ) {
355- break ;
359+ if (remaining) {
360+ --*remaining ;
356361 }
362+ } else {
363+ break ;
357364 }
358365 }
366+ return std::nullopt ;
359367}
360368
361369std::optional<char32_t > IoStatementState::NextInField (
@@ -372,6 +380,7 @@ std::optional<char32_t> IoStatementState::NextInField(
372380 case ' \' ' :
373381 case ' "' :
374382 case ' *' :
383+ case ' \n ' : // for stream access
375384 break ;
376385 default :
377386 HandleRelativePosition (1 );
@@ -385,7 +394,8 @@ std::optional<char32_t> IoStatementState::NextInField(
385394 return next;
386395 }
387396 const ConnectionState &connection{GetConnectionState ()};
388- if (!connection.IsAtEOF () && connection.recordLength &&
397+ if (!connection.IsAtEOF () && connection.isFixedRecordLength &&
398+ connection.recordLength &&
389399 connection.positionInRecord >= *connection.recordLength ) {
390400 if (connection.modes .pad ) { // PAD='YES'
391401 --*remaining;
@@ -553,29 +563,39 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
553563 return edit;
554564}
555565
566+ template <Direction DIR>
567+ bool UnformattedIoStatementState<DIR>::Receive(char *data, std::size_t bytes) {
568+ if constexpr (DIR == Direction::Output) {
569+ this ->Crash (
570+ " UnformattedIoStatementState::Receive() called for output statement" );
571+ }
572+ return this ->unit ().Receive (data, bytes, *this );
573+ }
574+
556575template <Direction DIR>
557576int UnformattedIoStatementState<DIR>::EndIoStatement() {
558- auto &ext{static_cast <ExternalIoStatementState<DIR> &>(*this )};
559- ExternalFileUnit &unit{ext.unit ()};
560- if (unit.access == Access::Sequential && !unit.recordLength .has_value ()) {
561- // Overwrite the first four bytes of the record with its length,
562- // and also append the length. These four bytes were skipped over
563- // in BeginUnformattedOutput().
564- // TODO: Break very large records up into subrecords with negative
565- // headers &/or footers
566- union {
567- std::uint32_t u;
568- char c[sizeof u];
569- } u;
570- u.u = unit.furthestPositionInRecord - sizeof u.c ;
571- // TODO: Convert record length to little-endian on big-endian host?
572- if (!(ext.Emit (u.c , sizeof u.c ) &&
573- (ext.HandleAbsolutePosition (0 ), ext.Emit (u.c , sizeof u.c )) &&
574- ext.AdvanceRecord ())) {
575- return false ;
577+ ExternalFileUnit &unit{this ->unit ()};
578+ if constexpr (DIR == Direction::Output) {
579+ if (unit.access == Access::Sequential && !unit.isFixedRecordLength ) {
580+ // Append the length of a sequential unformatted variable-length record
581+ // as its footer, then overwrite the reserved first four bytes of the
582+ // record with its length as its header. These four bytes were skipped
583+ // over in BeginUnformattedOutput().
584+ // TODO: Break very large records up into subrecords with negative
585+ // headers &/or footers
586+ union {
587+ std::uint32_t u;
588+ char c[sizeof u];
589+ } u;
590+ u.u = unit.furthestPositionInRecord - sizeof u;
591+ // TODO: Convert record length to little-endian on big-endian host?
592+ if (!(this ->Emit (u.c , sizeof u) &&
593+ (this ->HandleAbsolutePosition (0 ), this ->Emit (u.c , sizeof u)))) {
594+ return false ;
595+ }
576596 }
577597 }
578- return ext. EndIoStatement ();
598+ return ExternalIoStatementState<DIR>:: EndIoStatement ();
579599}
580600
581601template class InternalIoStatementState <Direction::Output>;
@@ -592,4 +612,25 @@ template class ExternalListIoStatementState<Direction::Output>;
592612template class ExternalListIoStatementState <Direction::Input>;
593613template class UnformattedIoStatementState <Direction::Output>;
594614template class UnformattedIoStatementState <Direction::Input>;
615+
616+ int ExternalMiscIoStatementState::EndIoStatement () {
617+ ExternalFileUnit &ext{unit ()};
618+ switch (which_) {
619+ case Flush:
620+ ext.Flush (*this );
621+ std::fflush (nullptr ); // flushes C stdio output streams (12.9(2))
622+ break ;
623+ case Backspace:
624+ ext.BackspaceRecord (*this );
625+ break ;
626+ case Endfile:
627+ ext.Endfile (*this );
628+ break ;
629+ case Rewind:
630+ ext.Rewind (*this );
631+ break ;
632+ }
633+ return ExternalIoStatementBase::EndIoStatement ();
634+ }
635+
595636} // namespace Fortran::runtime::io
0 commit comments