//===-- runtime/command.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Runtime/command.h" #include "environment.h" #include "stat.h" #include "terminator.h" #include "flang/Runtime/descriptor.h" #include #include namespace Fortran::runtime { std::int32_t RTNAME(ArgumentCount)() { int argc{executionEnvironment.argc}; if (argc > 1) { // C counts the command name as one of the arguments, but Fortran doesn't. return argc - 1; } return 0; } // Returns the length of the \p string. Assumes \p string is valid. static std::int64_t StringLength(const char *string) { std::size_t length{std::strlen(string)}; if constexpr (sizeof(std::size_t) <= sizeof(std::int64_t)) { return static_cast(length); } else { std::size_t max{std::numeric_limits::max()}; return length > max ? 0 // Just fail. : static_cast(length); } } std::int64_t RTNAME(ArgumentLength)(std::int32_t n) { if (n < 0 || n >= executionEnvironment.argc || !executionEnvironment.argv[n]) { return 0; } return StringLength(executionEnvironment.argv[n]); } static bool IsValidCharDescriptor(const Descriptor *value) { return value && value->IsAllocated() && value->type() == TypeCode(TypeCategory::Character, 1) && value->rank() == 0; } static void FillWithSpaces(const Descriptor *value) { std::memset(value->OffsetElement(), ' ', value->ElementBytes()); } static std::int32_t CopyToDescriptor(const Descriptor &value, const char *rawValue, std::int64_t rawValueLength, const Descriptor *errmsg) { std::int64_t toCopy{std::min( rawValueLength, static_cast(value.ElementBytes()))}; std::memcpy(value.OffsetElement(), rawValue, toCopy); if (rawValueLength > toCopy) { return ToErrmsg(errmsg, StatValueTooShort); } return StatOk; } std::int32_t RTNAME(ArgumentValue)( std::int32_t n, const Descriptor *value, const Descriptor *errmsg) { if (IsValidCharDescriptor(value)) { FillWithSpaces(value); } if (n < 0 || n >= executionEnvironment.argc) { return ToErrmsg(errmsg, StatInvalidArgumentNumber); } if (IsValidCharDescriptor(value)) { const char *arg{executionEnvironment.argv[n]}; std::int64_t argLen{StringLength(arg)}; if (argLen <= 0) { return ToErrmsg(errmsg, StatMissingArgument); } return CopyToDescriptor(*value, arg, argLen, errmsg); } return StatOk; } static std::size_t LengthWithoutTrailingSpaces(const Descriptor &d) { std::size_t s{d.ElementBytes() - 1}; while (*d.OffsetElement(s) == ' ') { --s; } return s + 1; } static const char *GetEnvVariableValue( const Descriptor &name, bool trim_name, const char *sourceFile, int line) { std::size_t nameLength{ trim_name ? LengthWithoutTrailingSpaces(name) : name.ElementBytes()}; if (nameLength == 0) { return nullptr; } Terminator terminator{sourceFile, line}; const char *value{executionEnvironment.GetEnv( name.OffsetElement(), nameLength, terminator)}; return value; } std::int32_t RTNAME(EnvVariableValue)(const Descriptor &name, const Descriptor *value, bool trim_name, const Descriptor *errmsg, const char *sourceFile, int line) { if (IsValidCharDescriptor(value)) { FillWithSpaces(value); } const char *rawValue{GetEnvVariableValue(name, trim_name, sourceFile, line)}; if (!rawValue) { return ToErrmsg(errmsg, StatMissingEnvVariable); } if (IsValidCharDescriptor(value)) { return CopyToDescriptor(*value, rawValue, StringLength(rawValue), errmsg); } return StatOk; } std::int64_t RTNAME(EnvVariableLength)( const Descriptor &name, bool trim_name, const char *sourceFile, int line) { const char *value{GetEnvVariableValue(name, trim_name, sourceFile, line)}; if (!value) { return 0; } return StringLength(value); } } // namespace Fortran::runtime