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 <cstdlib>
14 #include <limits>
15 
16 namespace Fortran::runtime {
17 std::int32_t RTNAME(ArgumentCount)() {
18   int argc{executionEnvironment.argc};
19   if (argc > 1) {
20     // C counts the command name as one of the arguments, but Fortran doesn't.
21     return argc - 1;
22   }
23   return 0;
24 }
25 
26 // Returns the length of the \p n'th argument. Assumes \p n is valid.
27 static std::int64_t ArgumentLength(std::int32_t n) {
28   std::size_t length{std::strlen(executionEnvironment.argv[n])};
29   if constexpr (sizeof(std::size_t) <= sizeof(std::int64_t)) {
30     return static_cast<std::int64_t>(length);
31   } else {
32     std::size_t max{std::numeric_limits<std::int64_t>::max()};
33     return length > max ? 0 // Just fail.
34                         : static_cast<std::int64_t>(length);
35   }
36 }
37 
38 std::int64_t RTNAME(ArgumentLength)(std::int32_t n) {
39   if (n < 0 || n >= executionEnvironment.argc) {
40     return 0;
41   }
42 
43   return ArgumentLength(n);
44 }
45 
46 static bool IsValidCharDescriptor(const Descriptor *value) {
47   return value && value->IsAllocated() &&
48       value->type() == TypeCode(TypeCategory::Character, 1) &&
49       value->rank() == 0;
50 }
51 
52 static void FillWithSpaces(const Descriptor *value) {
53   std::memset(value->OffsetElement(), ' ', value->ElementBytes());
54 }
55 
56 std::int32_t RTNAME(ArgumentValue)(
57     std::int32_t n, const Descriptor *value, const Descriptor *errmsg) {
58   if (IsValidCharDescriptor(value)) {
59     FillWithSpaces(value);
60   }
61 
62   if (n < 0 || n >= executionEnvironment.argc) {
63     return ToErrmsg(errmsg, StatInvalidArgumentNumber);
64   }
65 
66   if (IsValidCharDescriptor(value)) {
67     std::int64_t argLen{ArgumentLength(n)};
68     if (argLen <= 0) {
69       return ToErrmsg(errmsg, StatMissingArgument);
70     }
71 
72     std::int64_t toCopy{
73         std::min(argLen, static_cast<std::int64_t>(value->ElementBytes()))};
74     std::memcpy(value->OffsetElement(), executionEnvironment.argv[n], toCopy);
75 
76     if (argLen > toCopy) {
77       return ToErrmsg(errmsg, StatValueTooShort);
78     }
79   }
80 
81   return StatOk;
82 }
83 
84 static std::size_t LengthWithoutTrailingSpaces(const Descriptor &d) {
85   std::size_t s{d.ElementBytes() - 1};
86   while (*d.OffsetElement(s) == ' ') {
87     --s;
88   }
89   return s + 1;
90 }
91 
92 std::int64_t RTNAME(EnvVariableLength)(const Descriptor &name, bool trim_name) {
93   std::size_t nameLength{
94       trim_name ? LengthWithoutTrailingSpaces(name) : name.ElementBytes()};
95   if (nameLength == 0) {
96     return 0;
97   }
98 
99   const char *value{
100       executionEnvironment.GetEnv(name.OffsetElement(), nameLength)};
101   if (!value) {
102     return 0;
103   }
104   return std::strlen(value);
105 }
106 } // namespace Fortran::runtime
107