forked from OSchip/llvm-project
Introduce getenv to LLVM libc
Add support for getenv as defined by the Open Group's "System Interface & Header" in https://pubs.opengroup.org/onlinepubs/7908799/xsh/getenv.html getenv requires a standard way of accessing the environment, so a pointer to the environment is added to the startup in crt1. Consquently, this function is not usable on top of other libcs. Added starts_with method to StringView. getenv function uses it. Co-authored-by: Jeff Bailey <jeffbailey@google.com> Reviewed By: sivachandra, rtenneti Differential Revision: https://reviews.llvm.org/D119403
This commit is contained in:
parent
07b9a44515
commit
f2a7f83595
|
@ -33,8 +33,13 @@ struct AppProperties {
|
|||
|
||||
// The properties of an application's TLS.
|
||||
TLS tls;
|
||||
|
||||
// Environment data.
|
||||
uint64_t *envPtr;
|
||||
};
|
||||
|
||||
extern AppProperties app;
|
||||
|
||||
// Creates and initializes the TLS area for the current thread. Should not
|
||||
// be called before app.tls has been initialized.
|
||||
void initTLS();
|
||||
|
|
|
@ -72,6 +72,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
|||
libc.src.stdlib.atoll
|
||||
libc.src.stdlib.bsearch
|
||||
libc.src.stdlib.div
|
||||
libc.src.stdlib.getenv
|
||||
libc.src.stdlib.labs
|
||||
libc.src.stdlib.ldiv
|
||||
libc.src.stdlib.llabs
|
||||
|
|
|
@ -29,9 +29,6 @@ static constexpr long mmapSyscallNumber = SYS_mmap;
|
|||
#error "Target platform does not have SYS_mmap or SYS_mmap2 defined"
|
||||
#endif
|
||||
|
||||
// TODO: Declare var an extern var in config/linux/app.h so that other
|
||||
// libc functions can make use of the application wide information. For
|
||||
// example, mmap can pick up the page size from here.
|
||||
AppProperties app;
|
||||
|
||||
// TODO: The function is x86_64 specific. Move it to config/linux/app.h
|
||||
|
@ -109,6 +106,7 @@ extern "C" void _start() {
|
|||
// value. We step over it (the "+ 1" below) to get to the env values.
|
||||
uint64_t *env_ptr = args->argv + args->argc + 1;
|
||||
uint64_t *env_end_marker = env_ptr;
|
||||
app.envPtr = env_ptr;
|
||||
while (*env_end_marker)
|
||||
++env_end_marker;
|
||||
|
||||
|
|
|
@ -265,6 +265,20 @@ def POSIX : StandardSpec<"POSIX"> {
|
|||
]
|
||||
>;
|
||||
|
||||
HeaderSpec StdLib = HeaderSpec<
|
||||
"stdlib.h",
|
||||
[], // Macros
|
||||
[], // Types
|
||||
[], // Enumerations
|
||||
[
|
||||
FunctionSpec<
|
||||
"getenv",
|
||||
RetValSpec<CharPtr>,
|
||||
[ArgSpec<ConstCharPtr>]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
HeaderSpec String = HeaderSpec<
|
||||
"string.h",
|
||||
[
|
||||
|
@ -356,6 +370,7 @@ def POSIX : StandardSpec<"POSIX"> {
|
|||
Errno,
|
||||
FCntl,
|
||||
Signal,
|
||||
StdLib,
|
||||
SysMMan,
|
||||
SysStat,
|
||||
UniStd,
|
||||
|
|
|
@ -81,6 +81,17 @@ public:
|
|||
return remove_prefix(PrefixLen).remove_suffix(SuffixLen);
|
||||
}
|
||||
|
||||
// Check if this string starts with the given \p Prefix.
|
||||
bool starts_with(StringView Prefix) const {
|
||||
if (Len < Prefix.Len)
|
||||
return false;
|
||||
for (size_t I = 0; I < Prefix.Len; ++I) {
|
||||
if (Data[I] != Prefix.Data[I])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// An equivalent method is not available in std::string_view.
|
||||
bool equals(StringView Other) const {
|
||||
if (Len != Other.Len)
|
||||
|
|
|
@ -38,6 +38,17 @@ add_entrypoint_object(
|
|||
libc.src.__support.str_to_integer
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
getenv
|
||||
SRCS
|
||||
getenv.cpp
|
||||
HDRS
|
||||
getenv.h
|
||||
DEPENDS
|
||||
libc.config.linux.app_h
|
||||
libc.src.string.strncmp
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
strtof
|
||||
SRCS
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
//===-- Implementation of getenv ------------------------------------------===//
|
||||
//
|
||||
// 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 "src/stdlib/getenv.h"
|
||||
#include "config/linux/app.h"
|
||||
#include "src/__support/CPP/StringView.h"
|
||||
#include "src/__support/common.h"
|
||||
|
||||
#include <stddef.h> // For size_t.
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
LLVM_LIBC_FUNCTION(char *, getenv, (const char *name)) {
|
||||
char **env_ptr = reinterpret_cast<char **>(__llvm_libc::app.envPtr);
|
||||
|
||||
if (name == nullptr || env_ptr == nullptr)
|
||||
return nullptr;
|
||||
|
||||
__llvm_libc::cpp::StringView env_var_name(name);
|
||||
if (env_var_name.size() == 0)
|
||||
return nullptr;
|
||||
for (char **env = env_ptr; *env != nullptr; env++) {
|
||||
__llvm_libc::cpp::StringView cur(*env);
|
||||
if (!cur.starts_with(env_var_name))
|
||||
continue;
|
||||
|
||||
if (cur[env_var_name.size()] != '=')
|
||||
continue;
|
||||
|
||||
return const_cast<char *>(
|
||||
cur.remove_prefix(env_var_name.size() + 1).data());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for getenv --------------------------------*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC_STDLIB_GETENV_H
|
||||
#define LLVM_LIBC_SRC_STDLIB_GETENV_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
char *getenv(const char *name);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDLIB_GETENV_H
|
|
@ -43,6 +43,20 @@ add_loader_test(
|
|||
libc.loader.linux.crt1
|
||||
)
|
||||
|
||||
add_loader_test(
|
||||
getenv_test
|
||||
SRC
|
||||
getenv_test.cpp
|
||||
DEPENDS
|
||||
.loader_test
|
||||
libc.loader.linux.crt1
|
||||
libc.src.stdlib.getenv
|
||||
ENV
|
||||
FRANCE=Paris
|
||||
GERMANY=Berlin
|
||||
)
|
||||
|
||||
|
||||
# TODO: Disableing this test temporarily to investigate why gold fails to link
|
||||
# and produce an executable for this test. Test works all fine with ld.bfd.
|
||||
#add_loader_test(
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
//===-- Unittests for getenv ----------------------------------------------===//
|
||||
//
|
||||
// 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 "loader_test.h"
|
||||
#include "src/stdlib/getenv.h"
|
||||
|
||||
static bool my_streq(const char *lhs, const char *rhs) {
|
||||
if (lhs == rhs)
|
||||
return true;
|
||||
if (((lhs == static_cast<char *>(nullptr)) &&
|
||||
(rhs != static_cast<char *>(nullptr))) ||
|
||||
((lhs != static_cast<char *>(nullptr)) &&
|
||||
(rhs == static_cast<char *>(nullptr)))) {
|
||||
return false;
|
||||
}
|
||||
const char *l, *r;
|
||||
for (l = lhs, r = rhs; *l != '\0' && *r != '\0'; ++l, ++r)
|
||||
if (*l != *r)
|
||||
return false;
|
||||
|
||||
return *l == '\0' && *r == '\0';
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
ASSERT_TRUE(my_streq(__llvm_libc::getenv(""), static_cast<char *>(nullptr)));
|
||||
ASSERT_TRUE(my_streq(__llvm_libc::getenv("="), static_cast<char *>(nullptr)));
|
||||
ASSERT_TRUE(my_streq(__llvm_libc::getenv("MISSING ENV VARIABLE"),
|
||||
static_cast<char *>(nullptr)));
|
||||
ASSERT_FALSE(
|
||||
my_streq(__llvm_libc::getenv("PATH"), static_cast<char *>(nullptr)));
|
||||
ASSERT_TRUE(my_streq(__llvm_libc::getenv("FRANCE"), "Paris"));
|
||||
ASSERT_FALSE(my_streq(__llvm_libc::getenv("FRANCE"), "Berlin"));
|
||||
ASSERT_TRUE(my_streq(__llvm_libc::getenv("GERMANY"), "Berlin"));
|
||||
ASSERT_TRUE(
|
||||
my_streq(__llvm_libc::getenv("FRANC"), static_cast<char *>(nullptr)));
|
||||
ASSERT_TRUE(
|
||||
my_streq(__llvm_libc::getenv("FRANCE1"), static_cast<char *>(nullptr)));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -21,7 +21,17 @@
|
|||
__llvm_libc::quick_exit(127); \
|
||||
}
|
||||
|
||||
#define __CHECK_NE(file, line, val, should_exit) \
|
||||
if ((val)) { \
|
||||
__llvm_libc::write_to_stderr(file ":" __AS_STRING( \
|
||||
line) ": Expected '" #val "' to be false, but is true\n"); \
|
||||
if (should_exit) \
|
||||
__llvm_libc::quick_exit(127); \
|
||||
}
|
||||
|
||||
#define EXPECT_TRUE(val) __CHECK(__FILE__, __LINE__, val, false)
|
||||
#define ASSERT_TRUE(val) __CHECK(__FILE__, __LINE__, val, true)
|
||||
#define EXPECT_FALSE(val) __CHECK_NE(__FILE__, __LINE__, val, false)
|
||||
#define ASSERT_FALSE(val) __CHECK_NE(__FILE__, __LINE__, val, true)
|
||||
|
||||
#endif // LLVM_LIBC_TEST_LOADER_LINUX_LOADER_TEST_H
|
||||
|
|
|
@ -45,6 +45,19 @@ TEST(LlvmLibcStringViewTest, Equals) {
|
|||
ASSERT_FALSE(v.equals(__llvm_libc::cpp::StringView("abcde")));
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStringViewTest, startsWith) {
|
||||
__llvm_libc::cpp::StringView v("abc");
|
||||
ASSERT_TRUE(v.starts_with(__llvm_libc::cpp::StringView("a")));
|
||||
ASSERT_TRUE(v.starts_with(__llvm_libc::cpp::StringView("ab")));
|
||||
ASSERT_TRUE(v.starts_with(__llvm_libc::cpp::StringView("abc")));
|
||||
ASSERT_TRUE(v.starts_with(__llvm_libc::cpp::StringView()));
|
||||
ASSERT_TRUE(v.starts_with(__llvm_libc::cpp::StringView("")));
|
||||
ASSERT_FALSE(v.starts_with(__llvm_libc::cpp::StringView("123")));
|
||||
ASSERT_FALSE(v.starts_with(__llvm_libc::cpp::StringView("abd")));
|
||||
ASSERT_FALSE(v.starts_with(__llvm_libc::cpp::StringView("aaa")));
|
||||
ASSERT_FALSE(v.starts_with(__llvm_libc::cpp::StringView("abcde")));
|
||||
}
|
||||
|
||||
TEST(LlvmLibcStringViewTest, RemovePrefix) {
|
||||
__llvm_libc::cpp::StringView v("123456789");
|
||||
|
||||
|
|
Loading…
Reference in New Issue