blob: f7a342ccbb7368776af25b4a63c3988d9f971365 [file] [log] [blame]
peter klauslerf7be2512020-01-23 16:59:27 -08001//===-- runtime/unit.cpp ----------------------------------------*- 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#include "unit.h"
10#include "lock.h"
11#include "memory.h"
12#include "tools.h"
13#include <cerrno>
14#include <type_traits>
15
16namespace Fortran::runtime::io {
17
18static Lock mapLock;
19static Terminator mapTerminator;
20static Map<int, ExternalFile> unitMap{MapAllocator<int, ExternalFile>{mapTerminator}};
21
22ExternalFile *ExternalFile::LookUp(int unit) {
23 CriticalSection criticalSection{mapLock};
24 auto iter{unitMap.find(unit)};
25 return iter == unitMap.end() ? nullptr : &iter->second;
26}
27
28ExternalFile &ExternalFile::LookUpOrCrash(int unit, Terminator &terminator) {
29 CriticalSection criticalSection{mapLock};
30 ExternalFile *file{LookUp(unit)};
31 if (!file) {
32 terminator.Crash("Not an open I/O unit number: %d", unit);
33 }
34 return *file;
35}
36
37ExternalFile &ExternalFile::Create(int unit, Terminator &terminator) {
38 CriticalSection criticalSection{mapLock};
39 auto pair{unitMap.emplace(unit, unit)};
40 if (!pair.second) {
41 terminator.Crash("Already opened I/O unit number: %d", unit);
42 }
43 return pair.first->second;
44}
45
46void ExternalFile::CloseUnit(IoErrorHandler &handler) {
47 CriticalSection criticalSection{mapLock};
48 Flush(handler);
49 auto iter{unitMap.find(unitNumber_)};
50 if (iter != unitMap.end()) {
51 unitMap.erase(iter);
52 }
53}
54
55void ExternalFile::InitializePredefinedUnits(Terminator &terminator) {
56 ExternalFile &out{ExternalFile::Create(6, terminator)};
57 out.Predefine(1);
58 out.set_mayRead(false);
59 out.set_mayWrite(true);
60 out.set_mayPosition(false);
61 ExternalFile &in{ExternalFile::Create(5, terminator)};
62 in.Predefine(0);
63 in.set_mayRead(true);
64 in.set_mayWrite(false);
65 in.set_mayPosition(false);
66 // TODO: Set UTF-8 mode from the environment
67}
68
69void ExternalFile::CloseAll(IoErrorHandler &handler) {
70 CriticalSection criticalSection{mapLock};
71 while (!unitMap.empty()) {
72 auto &pair{*unitMap.begin()};
73 pair.second.CloseUnit(handler);
74 }
75}
76
77bool ExternalFile::SetPositionInRecord(std::int64_t n, IoErrorHandler &handler) {
78 n = std::max(std::int64_t{0}, n);
79 bool ok{true};
80 if (n > recordLength.value_or(n)) {
81 handler.SignalEor();
82 n = *recordLength;
83 ok = false;
84 }
85 if (n > furthestPositionInRecord) {
86 if (!isReading_ && ok) {
87 WriteFrame(recordOffsetInFile, n, handler);
88 std::fill_n(Frame() + furthestPositionInRecord, n - furthestPositionInRecord, ' ');
89 }
90 furthestPositionInRecord = n;
91 }
92 positionInRecord = n;
93 return ok;
94}
95
96bool ExternalFile::Emit(const char *data, std::size_t bytes, IoErrorHandler &handler) {
97 auto furthestAfter{std::max(furthestPositionInRecord, positionInRecord + static_cast<std::int64_t>(bytes))};
98 WriteFrame(recordOffsetInFile, furthestAfter, handler);
99 std::memcpy(Frame() + positionInRecord, data, bytes);
100 positionInRecord += bytes;
101 furthestPositionInRecord = furthestAfter;
102 return true;
103}
104
105void ExternalFile::SetLeftTabLimit() {
106 leftTabLimit = furthestPositionInRecord;
107 positionInRecord = furthestPositionInRecord;
108}
109
110bool ExternalFile::NextOutputRecord(IoErrorHandler &handler) {
111 bool ok{true};
112 if (recordLength.has_value()) { // fill fixed-size record
113 ok &= SetPositionInRecord(*recordLength, handler);
114 } else if (!unformatted && !isReading_) {
115 ok &= SetPositionInRecord(furthestPositionInRecord, handler) &&
116 Emit("\n", 1, handler);
117 }
118 recordOffsetInFile += furthestPositionInRecord;
119 ++currentRecordNumber;
120 positionInRecord = 0;
121 positionInRecord = furthestPositionInRecord = 0;
122 leftTabLimit.reset();
123 return ok;
124}
125
126bool ExternalFile::HandleAbsolutePosition(std::int64_t n, IoErrorHandler &handler) {
127 return SetPositionInRecord(std::max(n, std::int64_t{0}) + leftTabLimit.value_or(0), handler);
128}
129
130bool ExternalFile::HandleRelativePosition(std::int64_t n, IoErrorHandler &handler) {
131 return HandleAbsolutePosition(positionInRecord + n, handler);
132}
133
134void ExternalFile::EndIoStatement() {
135 u_.emplace<std::monostate>();
136}
137}