1 //===-- runtime/command.cpp -----------------------------------------------===//
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 "flang/Runtime/command.h"
10 #include "environment.h"
11 #include "stat.h"
12 #include "flang/Runtime/descriptor.h"
13 #include <limits>
14 
15 namespace Fortran::runtime {
16 std::int32_t RTNAME(ArgumentCount)() {
17   int argc{executionEnvironment.argc};
18   if (argc > 1) {
19     // C counts the command name as one of the arguments, but Fortran doesn't.
20     return argc - 1;
21   }
22   return 0;
23 }
24 
25 // Returns the length of the \p n'th argument. Assumes \p n is valid.
26 static std::int64_t ArgumentLength(std::int32_t n) {
27   std::size_t length{std::strlen(executionEnvironment.argv[n])};
28   if constexpr (sizeof(std::size_t) <= sizeof(std::int64_t)) {
29     return static_cast<std::int64_t>(length);
30   } else {
31     std::size_t max{std::numeric_limits<std::int64_t>::max()};
32     return length > max ? 0 // Just fail.
33                         : static_cast<std::int64_t>(length);
34   }
35 }
36 
37 std::int64_t RTNAME(ArgumentLength)(std::int32_t n) {
38   if (n < 0 || n >= executionEnvironment.argc) {
39     return 0;
40   }
41 
42   return ArgumentLength(n);
43 }
44 
45 static bool IsValidCharDescriptor(const Descriptor *value) {
46   return value && value->IsAllocated() &&
47       value->type() == TypeCode(TypeCategory::Character, 1) &&
48       value->rank() == 0;
49 }
50 
51 static void FillWithSpaces(const Descriptor *value) {
52   std::memset(value->OffsetElement(), ' ', value->ElementBytes());
53 }
54 
55 std::int32_t RTNAME(ArgumentValue)(
56     std::int32_t n, const Descriptor *value, const Descriptor *errmsg) {
57   if (IsValidCharDescriptor(value)) {
58     FillWithSpaces(value);
59   }
60 
61   if (n < 0 || n >= executionEnvironment.argc) {
62     return ToErrmsg(errmsg, StatInvalidArgumentNumber);
63   }
64 
65   if (IsValidCharDescriptor(value)) {
66     std::int64_t argLen{ArgumentLength(n)};
67     if (argLen <= 0) {
68       return ToErrmsg(errmsg, StatMissingArgument);
69     }
70 
71     std::int64_t toCopy{
72         std::min(argLen, static_cast<std::int64_t>(value->ElementBytes()))};
73     std::memcpy(value->OffsetElement(), executionEnvironment.argv[n], toCopy);
74 
75     if (argLen > toCopy) {
76       return ToErrmsg(errmsg, StatValueTooShort);
77     }
78   }
79 
80   return StatOk;
81 }
82 } // namespace Fortran::runtime
83