diff --git a/flang/include/flang/Runtime/command.h b/flang/include/flang/Runtime/command.h --- a/flang/include/flang/Runtime/command.h +++ b/flang/include/flang/Runtime/command.h @@ -9,9 +9,10 @@ #ifndef FORTRAN_RUNTIME_COMMAND_H_ #define FORTRAN_RUNTIME_COMMAND_H_ -#include "flang/Runtime/cpp-type.h" #include "flang/Runtime/entry-names.h" +#include + namespace Fortran::runtime { class Descriptor; @@ -20,7 +21,7 @@ // // Lowering may need to cast the result to match the precision of the default // integer kind. -CppTypeFor RTNAME(ArgumentCount)(); +std::int32_t RTNAME(ArgumentCount)(); // 16.9.83 GET_COMMAND_ARGUMENT // We're breaking up the interface into several different functions, since most @@ -28,14 +29,12 @@ // Try to get the value of the n'th argument. // Returns a STATUS as described in the standard. -CppTypeFor RTNAME(ArgumentValue)( - CppTypeFor n, const Descriptor *value, - const Descriptor *errmsg); +std::int32_t RTNAME(ArgumentValue)( + std::int32_t n, const Descriptor *value, const Descriptor *errmsg); // Try to get the significant length of the n'th argument. // Returns 0 if it doesn't manage. -CppTypeFor RTNAME(ArgumentLength)( - CppTypeFor n); +std::int64_t RTNAME(ArgumentLength)(std::int32_t n); } } // namespace Fortran::runtime diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp --- a/flang/runtime/command.cpp +++ b/flang/runtime/command.cpp @@ -8,9 +8,10 @@ #include "flang/Runtime/command.h" #include "environment.h" +#include namespace Fortran::runtime { -CppTypeFor RTNAME(ArgumentCount)() { +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. @@ -18,4 +19,19 @@ } return 0; } + +std::int64_t RTNAME(ArgumentLength)(std::int32_t n) { + if (n < 0 || n >= executionEnvironment.argc) { + return 0; + } + + std::size_t length{std::strlen(executionEnvironment.argv[n])}; + 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); + } +} } // namespace Fortran::runtime diff --git a/flang/test/Runtime/no-cpp-dep.c b/flang/test/Runtime/no-cpp-dep.c --- a/flang/test/Runtime/no-cpp-dep.c +++ b/flang/test/Runtime/no-cpp-dep.c @@ -5,19 +5,29 @@ REQUIRES: c-compiler -RUN: %cc -std=c90 %s -I%include %libruntime %libdecimal -o /dev/null +RUN: %cc -std=c99 %s -I%include %libruntime %libdecimal -lm -o /dev/null */ #include "flang/Runtime/entry-names.h" +#include /* Manually add declarations for the runtime functions that we want to make sure we're testing. We can't include any headers directly since they likely contain C++ code that would explode here. */ +struct Descriptor; + double RTNAME(CpuTime)(); +void RTNAME(ProgramStart)(int, const char *[], const char *[]); +int32_t RTNAME(ArgumentCount)(); +int64_t RTNAME(ArgumentLength)(int32_t); + int main() { double x = RTNAME(CpuTime)(); - return x; + RTNAME(ProgramStart)(0, 0, 0); + int32_t c = RTNAME(ArgumentCount)(); + int32_t l = RTNAME(ArgumentLength)(0); + return x + c + l; } diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp --- a/flang/unittests/Runtime/CommandTest.cpp +++ b/flang/unittests/Runtime/CommandTest.cpp @@ -13,20 +13,61 @@ using namespace Fortran::runtime; -TEST(ArgumentCount, ZeroArguments) { - const char *argv[]{"aProgram"}; - RTNAME(ProgramStart)(1, argv, {}); - EXPECT_EQ(0, RTNAME(ArgumentCount)()); +class CommandFixture : public ::testing::Test { +protected: + CommandFixture(int argc, const char *argv[]) { + RTNAME(ProgramStart)(argc, argv, {}); + } +}; + +static const char *commandOnlyArgv[]{"aProgram"}; +class ZeroArguments : public CommandFixture { +protected: + ZeroArguments() : CommandFixture(1, commandOnlyArgv) {} +}; + +TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); } + +TEST_F(ZeroArguments, ArgumentLength) { + EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); + EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); + EXPECT_EQ(0, RTNAME(ArgumentLength)(1)); } -TEST(ArgumentCount, OneArgument) { - const char *argv[]{"aProgram", "anArgument"}; - RTNAME(ProgramStart)(2, argv, {}); - EXPECT_EQ(1, RTNAME(ArgumentCount)()); +static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"}; +class OneArgument : public CommandFixture { +protected: + OneArgument() : CommandFixture(2, oneArgArgv) {} +}; + +TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); } + +TEST_F(OneArgument, ArgumentLength) { + EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); + EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); + EXPECT_EQ(20, RTNAME(ArgumentLength)(1)); + EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); } -TEST(ArgumentCount, SeveralArguments) { - const char *argv[]{"aProgram", "arg1", "arg2", "arg3", "arg4"}; - RTNAME(ProgramStart)(5, argv, {}); +static const char *severalArgsArgv[]{ + "aProgram", "16-char-long-arg", "", "-22-character-long-arg", "o"}; +class SeveralArguments : public CommandFixture { +protected: + SeveralArguments() + : CommandFixture(sizeof(severalArgsArgv) / sizeof(*severalArgsArgv), + severalArgsArgv) {} +}; + +TEST_F(SeveralArguments, ArgumentCount) { EXPECT_EQ(4, RTNAME(ArgumentCount)()); } + +TEST_F(SeveralArguments, ArgumentLength) { + EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); + EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); + EXPECT_EQ(16, RTNAME(ArgumentLength)(1)); + EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); + EXPECT_EQ(22, RTNAME(ArgumentLength)(3)); + EXPECT_EQ(1, RTNAME(ArgumentLength)(4)); + EXPECT_EQ(0, RTNAME(ArgumentLength)(5)); +}