[flang-commits] [flang] fc2ba5e - [flang] Implement GET_ENVIRONMENT_VARIABLE(LENGTH)

Diana Picus via flang-commits flang-commits at lists.llvm.org
Wed Oct 13 01:45:47 PDT 2021


Author: Diana Picus
Date: 2021-10-13T08:42:03Z
New Revision: fc2ba5e53d47a07f505ddee2441b3768e446624c

URL: https://github.com/llvm/llvm-project/commit/fc2ba5e53d47a07f505ddee2441b3768e446624c
DIFF: https://github.com/llvm/llvm-project/commit/fc2ba5e53d47a07f505ddee2441b3768e446624c.diff

LOG: [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

Added: 
    

Modified: 
    flang/runtime/command.cpp
    flang/runtime/environment.cpp
    flang/runtime/environment.h
    flang/unittests/Runtime/CommandTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index 5fc2d28305ffb..81daf64b6b7e7 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -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

diff  --git a/flang/runtime/environment.cpp b/flang/runtime/environment.cpp
index badcbbca562f0..2ba8faf6882ce 100644
--- a/flang/runtime/environment.cpp
+++ b/flang/runtime/environment.cpp
@@ -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

diff  --git a/flang/runtime/environment.h b/flang/runtime/environment.h
index 5e6b7b85b7272..1d04cb110b378 100644
--- a/flang/runtime/environment.h
+++ b/flang/runtime/environment.h
@@ -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;

diff  --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index a13addd75a214..194860f8797a7 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -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("     ")));
+}


        


More information about the flang-commits mailing list