[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:
parent
665970d421
commit
fc2ba5e53d
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(" ")));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue