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 string. Assumes \p string is valid. 28 static std::int64_t StringLength(const char *string) { 29 std::size_t length{std::strlen(string)}; 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 !executionEnvironment.argv[n]) { 42 return 0; 43 } 44 45 return StringLength(executionEnvironment.argv[n]); 46 } 47 48 static bool IsValidCharDescriptor(const Descriptor *value) { 49 return value && value->IsAllocated() && 50 value->type() == TypeCode(TypeCategory::Character, 1) && 51 value->rank() == 0; 52 } 53 54 static void FillWithSpaces(const Descriptor *value) { 55 std::memset(value->OffsetElement(), ' ', value->ElementBytes()); 56 } 57 58 static std::int32_t CopyToDescriptor(const Descriptor &value, 59 const char *rawValue, std::int64_t rawValueLength, 60 const Descriptor *errmsg) { 61 std::int64_t toCopy{std::min( 62 rawValueLength, static_cast<std::int64_t>(value.ElementBytes()))}; 63 std::memcpy(value.OffsetElement(), rawValue, toCopy); 64 65 if (rawValueLength > toCopy) { 66 return ToErrmsg(errmsg, StatValueTooShort); 67 } 68 69 return StatOk; 70 } 71 72 std::int32_t RTNAME(ArgumentValue)( 73 std::int32_t n, const Descriptor *value, const Descriptor *errmsg) { 74 if (IsValidCharDescriptor(value)) { 75 FillWithSpaces(value); 76 } 77 78 if (n < 0 || n >= executionEnvironment.argc) { 79 return ToErrmsg(errmsg, StatInvalidArgumentNumber); 80 } 81 82 if (IsValidCharDescriptor(value)) { 83 const char *arg{executionEnvironment.argv[n]}; 84 std::int64_t argLen{StringLength(arg)}; 85 if (argLen <= 0) { 86 return ToErrmsg(errmsg, StatMissingArgument); 87 } 88 89 return CopyToDescriptor(*value, arg, argLen, errmsg); 90 } 91 92 return StatOk; 93 } 94 95 static std::size_t LengthWithoutTrailingSpaces(const Descriptor &d) { 96 std::size_t s{d.ElementBytes() - 1}; 97 while (*d.OffsetElement(s) == ' ') { 98 --s; 99 } 100 return s + 1; 101 } 102 103 static const char *GetEnvVariableValue( 104 const Descriptor &name, bool trim_name, const char *sourceFile, int line) { 105 std::size_t nameLength{ 106 trim_name ? LengthWithoutTrailingSpaces(name) : name.ElementBytes()}; 107 if (nameLength == 0) { 108 return nullptr; 109 } 110 111 Terminator terminator{sourceFile, line}; 112 const char *value{executionEnvironment.GetEnv( 113 name.OffsetElement(), nameLength, terminator)}; 114 return value; 115 } 116 117 std::int32_t RTNAME(EnvVariableValue)(const Descriptor &name, 118 const Descriptor *value, bool trim_name, const Descriptor *errmsg, 119 const char *sourceFile, int line) { 120 if (IsValidCharDescriptor(value)) { 121 FillWithSpaces(value); 122 } 123 124 const char *rawValue{GetEnvVariableValue(name, trim_name, sourceFile, line)}; 125 if (!rawValue) { 126 return ToErrmsg(errmsg, StatMissingEnvVariable); 127 } 128 129 if (IsValidCharDescriptor(value)) { 130 return CopyToDescriptor(*value, rawValue, StringLength(rawValue), errmsg); 131 } 132 133 return StatOk; 134 } 135 136 std::int64_t RTNAME(EnvVariableLength)( 137 const Descriptor &name, bool trim_name, const char *sourceFile, int line) { 138 const char *value{GetEnvVariableValue(name, trim_name, sourceFile, line)}; 139 if (!value) { 140 return 0; 141 } 142 return StringLength(value); 143 } 144 } // namespace Fortran::runtime 145