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