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