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