diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -427,6 +427,7 @@ libc.src.stdio.fgetc_unlocked libc.src.stdio.fgets libc.src.stdio.fflush + libc.src.stdio.fileno libc.src.stdio.fopen libc.src.stdio.fputc libc.src.stdio.fputs diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -1121,6 +1121,11 @@ [], // Types [], // Enumerations [ + FunctionSpec< + "fileno", + RetValSpec, + [ArgSpec] + >, FunctionSpec< "flockfile", RetValSpec, diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -149,6 +149,19 @@ libc.src.__support.File.platform_file ) +add_entrypoint_object( + fileno + SRCS + fileno.cpp + HDRS + fileno.h + DEPENDS + libc.src.errno.errno + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + add_entrypoint_object( getc SRCS diff --git a/libc/src/stdio/fileno.h b/libc/src/stdio/fileno.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fileno.h @@ -0,0 +1,20 @@ +//===-- Implementation header of fileno -------------------------*- C++ -*-===// +// +// 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_STDIO_FILENO_H +#define LLVM_LIBC_SRC_STDIO_FILENO_H + +#include + +namespace __llvm_libc { + +int fileno(::FILE *stream); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_FILENO_H diff --git a/libc/src/stdio/fileno.cpp b/libc/src/stdio/fileno.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fileno.cpp @@ -0,0 +1,28 @@ +//===-- Implementation of fileno ------------------------------------------===// +// +// 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/stdio/fileno.h" +#include "src/__support/File/file.h" + +#include "src/errno/libc_errno.h" +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, fileno, (::FILE *__restrict stream)) { + auto fd = get_fileno(reinterpret_cast<__llvm_libc::File *>(stream)); + + if (fd >= 0) { + return fd; + } else { + libc_errno = EBADF; + return -1; + } +} + +} // namespace __llvm_libc diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -366,6 +366,18 @@ libc.src.stdio.fwrite ) +add_libc_unittest( + fileno_test + SUITE + libc_stdio_unittests + SRCS + fileno_test.cpp + DEPENDS + libc.include.stdio + libc.src.stdio.fopen + libc.src.stdio.fileno +) + add_libc_unittest( ftell_test SUITE diff --git a/libc/test/src/stdio/fileno_test.cpp b/libc/test/src/stdio/fileno_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdio/fileno_test.cpp @@ -0,0 +1,33 @@ +//===-- Unittests for fileno ----------------------------------------------===// +// +// 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/__support/File/file.h" +#include "src/stdio/fileno.h" +#include "src/stdio/fopen.h" +#include "test/UnitTest/Test.h" +#include + +TEST(LlvmLibcFilenoTest, ValidFilenoTest) { + ::FILE *file = __llvm_libc::fopen("testdata/test_data.txt", "w"); + ASSERT_FALSE(file == nullptr); + + // file descriptors associated with the streams stdin, stdout, and stderr are + // 0, 1, and 2, respectively. Therefore any newly opened file should have an + // integer file descriptor >= 3 + + ASSERT_FALSE(__llvm_libc::fileno(file) < 3); +} + +TEST(LlvmLibcFilenoTest, StandardStreamTest) { + ASSERT_EQ(__llvm_libc::fileno(reinterpret_cast(__llvm_libc::stdin)), + 0); + ASSERT_EQ(__llvm_libc::fileno(reinterpret_cast(__llvm_libc::stdout)), + 1); + ASSERT_EQ(__llvm_libc::fileno(reinterpret_cast(__llvm_libc::stderr)), + 2); +}