[flang] Implement GET_ENVIRONMENT_VARIABLE(LENGTH)

Search for the environment variable in the envp string passed to
ProgramStart. This doesn't work if the main program isn't Fortran.

Differential Revision: https://reviews.llvm.org/D111394
This commit is contained in:
Diana Picus 2021-10-07 13:44:14 +00:00
parent 665970d421
commit fc2ba5e53d
4 changed files with 79 additions and 0 deletions

View File

@ -10,6 +10,7 @@
#include "environment.h"
#include "stat.h"
#include "flang/Runtime/descriptor.h"
#include <cstdlib>
#include <limits>
namespace Fortran::runtime {
@ -79,4 +80,27 @@ std::int32_t RTNAME(ArgumentValue)(
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;
}
std::int64_t RTNAME(EnvVariableLength)(const Descriptor &name, bool trim_name) {
std::size_t nameLength{
trim_name ? LengthWithoutTrailingSpaces(name) : name.ElementBytes()};
if (nameLength == 0) {
return 0;
}
const char *value{
executionEnvironment.GetEnv(name.OffsetElement(), nameLength)};
if (!value) {
return 0;
}
return std::strlen(value);
}
} // namespace Fortran::runtime

View File

@ -68,4 +68,28 @@ void ExecutionEnvironment::Configure(
// TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
}
const char *ExecutionEnvironment::GetEnv(
const char *name, std::size_t name_length) {
if (!envp) {
// TODO: Ask std::getenv.
return nullptr;
}
// envp is an array of strings of the form "name=value".
for (const char **var{envp}; *var != nullptr; ++var) {
const char *eq{std::strchr(*var, '=')};
if (!eq) {
// Found a malformed environment string, just ignore it.
continue;
}
if (static_cast<std::size_t>(eq - *var) != name_length) {
continue;
}
if (std::memcmp(*var, name, name_length) == 0) {
return eq + 1;
}
}
return nullptr;
}
} // namespace Fortran::runtime

View File

@ -29,6 +29,7 @@ std::optional<Convert> GetConvertFromString(const char *, std::size_t);
struct ExecutionEnvironment {
void Configure(int argc, const char *argv[], const char *envp[]);
const char *GetEnv(const char *name, std::size_t name_length);
int argc;
const char **argv;

View File

@ -24,12 +24,25 @@ static OwningPtr<Descriptor> CreateEmptyCharDescriptor() {
return descriptor;
}
static OwningPtr<Descriptor> CharDescriptor(const char *value) {
std::size_t n{std::strlen(value)};
OwningPtr<Descriptor> descriptor{Descriptor::Create(
sizeof(char), n, nullptr, 0, nullptr, CFI_attribute_allocatable)};
if (descriptor->Allocate() != 0) {
return nullptr;
}
std::memcpy(descriptor->OffsetElement(), value, n);
return descriptor;
}
class CommandFixture : public ::testing::Test {
protected:
CommandFixture(int argc, const char *argv[]) {
RTNAME(ProgramStart)(argc, argv, {});
}
CommandFixture(const char *envp[]) { RTNAME(ProgramStart)(0, nullptr, envp); }
std::string GetPaddedStr(const char *text, std::size_t len) const {
std::string res{text};
assert(res.length() <= len && "No room to pad");
@ -175,3 +188,20 @@ TEST_F(SeveralArguments, ErrMsgTooShort) {
EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, errMsg.get()), 0);
CheckDescriptorEqStr(errMsg.get(), "Inv");
}
static const char *env[]{"NAME=value", nullptr};
class EnvironmentVariables : public CommandFixture {
protected:
EnvironmentVariables() : CommandFixture(env) {}
};
TEST_F(EnvironmentVariables, Length) {
EXPECT_EQ(5, RTNAME(EnvVariableLength)(*CharDescriptor("NAME")));
EXPECT_EQ(0, RTNAME(EnvVariableLength)(*CharDescriptor("DOESNT_EXIST")));
EXPECT_EQ(5, RTNAME(EnvVariableLength)(*CharDescriptor("NAME ")));
EXPECT_EQ(0,
RTNAME(EnvVariableLength)(*CharDescriptor("NAME "), /*trim_name=*/false));
EXPECT_EQ(0, RTNAME(EnvVariableLength)(*CharDescriptor(" ")));
}