1010#include " environment.h"
1111#include " stat.h"
1212#include " terminator.h"
13+ #include " tools.h"
1314#include " flang/Runtime/descriptor.h"
1415#include < cstdlib>
1516#include < limits>
@@ -51,16 +52,32 @@ static bool IsValidCharDescriptor(const Descriptor *value) {
5152 value->rank () == 0 ;
5253}
5354
54- static void FillWithSpaces (const Descriptor *value) {
55- std::memset (value->OffsetElement (), ' ' , value->ElementBytes ());
55+ static bool IsValidIntDescriptor (const Descriptor *length) {
56+ auto typeCode{length->type ().GetCategoryAndKind ()};
57+ // Check that our descriptor is allocated and is a scalar integer with
58+ // kind != 1 (i.e. with a large enough decimal exponent range).
59+ return length->IsAllocated () && length->rank () == 0 &&
60+ length->type ().IsInteger () && typeCode && typeCode->second != 1 ;
61+ }
62+
63+ static void FillWithSpaces (const Descriptor &value, std::size_t offset = 0 ) {
64+ if (offset < value.ElementBytes ()) {
65+ std::memset (
66+ value.OffsetElement (offset), ' ' , value.ElementBytes () - offset);
67+ }
5668}
5769
5870static std::int32_t CopyToDescriptor (const Descriptor &value,
59- const char *rawValue, std::int64_t rawValueLength,
60- const Descriptor *errmsg) {
61- std::int64_t toCopy{std::min (
62- rawValueLength, static_cast <std::int64_t >(value.ElementBytes ()))};
63- std::memcpy (value.OffsetElement (), rawValue, toCopy);
71+ const char *rawValue, std::int64_t rawValueLength, const Descriptor *errmsg,
72+ std::size_t offset = 0 ) {
73+
74+ std::int64_t toCopy{std::min (rawValueLength,
75+ static_cast <std::int64_t >(value.ElementBytes () - offset))};
76+ if (toCopy < 0 ) {
77+ return ToErrmsg (errmsg, StatValueTooShort);
78+ }
79+
80+ std::memcpy (value.OffsetElement (offset), rawValue, toCopy);
6481
6582 if (rawValueLength > toCopy) {
6683 return ToErrmsg (errmsg, StatValueTooShort);
@@ -69,10 +86,31 @@ static std::int32_t CopyToDescriptor(const Descriptor &value,
6986 return StatOk;
7087}
7188
89+ static std::int32_t CheckAndCopyToDescriptor (const Descriptor *value,
90+ const char *rawValue, const Descriptor *errmsg, std::size_t &offset) {
91+ bool haveValue{IsValidCharDescriptor (value)};
92+
93+ std::int64_t len{StringLength (rawValue)};
94+ if (len <= 0 ) {
95+ if (haveValue) {
96+ FillWithSpaces (*value);
97+ }
98+ return ToErrmsg (errmsg, StatMissingArgument);
99+ }
100+
101+ std::int32_t stat{StatOk};
102+ if (haveValue) {
103+ stat = CopyToDescriptor (*value, rawValue, len, errmsg, offset);
104+ }
105+
106+ offset += len;
107+ return stat;
108+ }
109+
72110std::int32_t RTNAME (ArgumentValue)(
73111 std::int32_t n, const Descriptor *value, const Descriptor *errmsg) {
74112 if (IsValidCharDescriptor (value)) {
75- FillWithSpaces (value);
113+ FillWithSpaces (* value);
76114 }
77115
78116 if (n < 0 || n >= executionEnvironment.argc ) {
@@ -92,6 +130,87 @@ std::int32_t RTNAME(ArgumentValue)(
92130 return StatOk;
93131}
94132
133+ template <int KIND> struct FitsInIntegerKind {
134+ bool operator ()(std::int64_t value) {
135+ return value <= std::numeric_limits<Fortran::runtime::CppTypeFor<
136+ Fortran::common::TypeCategory::Integer, KIND>>::max ();
137+ }
138+ };
139+
140+ std::int32_t RTNAME (GetCommand)(const Descriptor *value,
141+ const Descriptor *length, const Descriptor *errmsg, const char *sourceFile,
142+ int line) {
143+ Terminator terminator{sourceFile, line};
144+
145+ auto storeLength = [&](std::int64_t value) {
146+ auto typeCode{length->type ().GetCategoryAndKind ()};
147+ int kind{typeCode->second };
148+ Fortran::runtime::ApplyIntegerKind<Fortran::runtime::StoreIntegerAt, void >(
149+ kind, terminator, *length, /* atIndex = */ 0 , value);
150+ };
151+
152+ if (value) {
153+ RUNTIME_CHECK (terminator, IsValidCharDescriptor (value));
154+ }
155+
156+ // Store 0 in case we error out later on.
157+ if (length) {
158+ RUNTIME_CHECK (terminator, IsValidIntDescriptor (length));
159+ storeLength (0 );
160+ }
161+
162+ auto shouldContinue = [&](std::int32_t stat) -> bool {
163+ // We continue as long as everything is ok OR the value descriptor is
164+ // too short, but we still need to compute the length.
165+ return stat == StatOk || (length && stat == StatValueTooShort);
166+ };
167+
168+ std::size_t offset{0 };
169+
170+ if (executionEnvironment.argc == 0 ) {
171+ return CheckAndCopyToDescriptor (value, " " , errmsg, offset);
172+ }
173+
174+ // value = argv[0]
175+ std::int32_t stat{CheckAndCopyToDescriptor (
176+ value, executionEnvironment.argv [0 ], errmsg, offset)};
177+ if (!shouldContinue (stat)) {
178+ return stat;
179+ }
180+
181+ // value += " " + argv[1:n]
182+ for (std::int32_t i{1 }; i < executionEnvironment.argc ; ++i) {
183+ stat = CheckAndCopyToDescriptor (value, " " , errmsg, offset);
184+ if (!shouldContinue (stat)) {
185+ return stat;
186+ }
187+
188+ stat = CheckAndCopyToDescriptor (
189+ value, executionEnvironment.argv [i], errmsg, offset);
190+ if (!shouldContinue (stat)) {
191+ return stat;
192+ }
193+ }
194+
195+ auto fitsInLength = [&](std::int64_t value) -> bool {
196+ auto typeCode{length->type ().GetCategoryAndKind ()};
197+ int kind{typeCode->second };
198+ return Fortran::runtime::ApplyIntegerKind<FitsInIntegerKind, bool >(
199+ kind, terminator, value);
200+ };
201+
202+ if (length && fitsInLength (offset)) {
203+ storeLength (offset);
204+ }
205+
206+ // value += spaces for padding
207+ if (value) {
208+ FillWithSpaces (*value, offset);
209+ }
210+
211+ return stat;
212+ }
213+
95214static std::size_t LengthWithoutTrailingSpaces (const Descriptor &d) {
96215 std::size_t s{d.ElementBytes () - 1 };
97216 while (*d.OffsetElement (s) == ' ' ) {
@@ -118,7 +237,7 @@ std::int32_t RTNAME(EnvVariableValue)(const Descriptor &name,
118237 const Descriptor *value, bool trim_name, const Descriptor *errmsg,
119238 const char *sourceFile, int line) {
120239 if (IsValidCharDescriptor (value)) {
121- FillWithSpaces (value);
240+ FillWithSpaces (* value);
122241 }
123242
124243 const char *rawValue{GetEnvVariableValue (name, trim_name, sourceFile, line)};
0 commit comments