[libc-commits] [libc] 43e52ad - [libc] Add implementations of ftell.

Siva Chandra Reddy via libc-commits libc-commits at lists.llvm.org
Mon Nov 7 13:39:13 PST 2022


Author: Siva Chandra Reddy
Date: 2022-11-07T21:38:53Z
New Revision: 43e52ad553cbafb78386e9e6e1204c8de8a506d4

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

LOG: [libc] Add implementations of ftell.

Reviewed By: michaelrj, lntue

Differential Revision: https://reviews.llvm.org/D137395

Added: 
    libc/src/stdio/ftell.cpp
    libc/src/stdio/ftell.h
    libc/test/src/stdio/ftell_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/CMakeLists.txt
    libc/spec/stdc.td
    libc/src/__support/File/file.cpp
    libc/src/__support/File/file.h
    libc/src/__support/File/linux_file.cpp
    libc/src/stdio/CMakeLists.txt
    libc/src/stdio/fopencookie.cpp
    libc/test/src/__support/File/file_test.cpp
    libc/test/src/stdio/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 2c4867f48b1b9..8349af0e54e2a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -385,6 +385,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.stdio.fread
     libc.src.stdio.fread_unlocked
     libc.src.stdio.fseek
+    libc.src.stdio.ftell
     libc.src.stdio.funlockfile
     libc.src.stdio.fwrite
     libc.src.stdio.fwrite_unlocked

diff  --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index ac4e57572a696..f9d3ee5164f95 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -162,6 +162,7 @@ add_gen_header(
     .llvm-libc-macros.stdio_macros
     .llvm-libc-types.cookie_io_functions_t
     .llvm-libc-types.FILE
+    .llvm-libc-types.off_t
     .llvm-libc-types.size_t
 )
 

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 64ee9b7c45399..bb3f9a1c701b7 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -563,6 +563,11 @@ def StdC : StandardSpec<"stdc"> {
               [ArgSpec<IntType>,
                ArgSpec<FILEPtr>]
           >,
+          FunctionSpec<
+              "ftell",
+              RetValSpec<LongType>,
+              [ArgSpec<FILEPtr>]
+          >,
           FunctionSpec<
               "putc",
               RetValSpec<IntType>,

diff  --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index 9129f68b521d4..edb2467929f2d 100644
--- a/libc/src/__support/File/file.cpp
+++ b/libc/src/__support/File/file.cpp
@@ -294,7 +294,28 @@ int File::seek(long offset, int whence) {
   // Reset the eof flag as a seek might move the file positon to some place
   // readable.
   eof = false;
-  return platform_seek(this, offset, whence);
+  long platform_pos = platform_seek(this, offset, whence);
+  if (platform_pos >= 0)
+    return 0;
+  else
+    return -1;
+}
+
+long File::tell() {
+  FileLock lock(this);
+  long platform_offset;
+  if (eof)
+    platform_offset = platform_seek(this, 0, SEEK_END);
+  else
+    platform_offset = platform_seek(this, 0, SEEK_CUR);
+  if (platform_offset < 0)
+    return -1;
+  if (prev_op == FileOp::READ)
+    return platform_offset - (read_limit - pos);
+  else if (prev_op == FileOp::WRITE)
+    return platform_offset + pos;
+  else
+    return platform_offset;
 }
 
 int File::flush_unlocked() {

diff  --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index e08508bcb1d83..d182ea4c81b4d 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -28,7 +28,9 @@ class File {
 
   using WriteFunc = size_t(File *, const void *, size_t);
   using ReadFunc = size_t(File *, void *, size_t);
-  using SeekFunc = int(File *, long, int);
+  // The SeekFunc is expected to return the current offset of the external
+  // file position indicator.
+  using SeekFunc = long(File *, long, int);
   using CloseFunc = int(File *);
   using FlushFunc = int(File *);
 
@@ -191,6 +193,8 @@ class File {
 
   int seek(long offset, int whence);
 
+  long tell();
+
   // If buffer has data written to it, flush it out. Does nothing if the
   // buffer is currently being used as a read buffer.
   int flush() {
@@ -283,6 +287,10 @@ class File {
 // library.
 File *openfile(const char *path, const char *mode);
 
+// The platform_file library should implement it if it relevant for that
+// platform.
+int get_fileno(File *f);
+
 extern File *stdin;
 extern File *stdout;
 extern File *stderr;

diff  --git a/libc/src/__support/File/linux_file.cpp b/libc/src/__support/File/linux_file.cpp
index c6c93c8ef5086..09a880743baf4 100644
--- a/libc/src/__support/File/linux_file.cpp
+++ b/libc/src/__support/File/linux_file.cpp
@@ -22,7 +22,7 @@ namespace {
 
 size_t write_func(File *, const void *, size_t);
 size_t read_func(File *, void *, size_t);
-int seek_func(File *, long, int);
+long seek_func(File *, long, int);
 int close_func(File *);
 int flush_func(File *);
 
@@ -71,10 +71,12 @@ size_t read_func(File *f, void *buf, size_t size) {
   return ret;
 }
 
-int seek_func(File *f, long offset, int whence) {
+long seek_func(File *f, long offset, int whence) {
   auto *lf = reinterpret_cast<LinuxFile *>(f);
+  long result;
 #ifdef SYS_lseek
   long ret = __llvm_libc::syscall_impl(SYS_lseek, lf->get_fd(), offset, whence);
+  result = ret;
 #elif defined(SYS__llseek)
   long result;
   long ret = __llvm_libc::syscall_impl(SYS__llseek, lf->get_fd(), offset >> 32,
@@ -87,7 +89,7 @@ int seek_func(File *f, long offset, int whence) {
     errno = -ret;
     return -1;
   }
-  return 0;
+  return result;
 }
 
 int close_func(File *f) {
@@ -164,6 +166,11 @@ File *openfile(const char *path, const char *mode) {
   return file;
 }
 
+int get_fileno(File *f) {
+  auto *lf = reinterpret_cast<LinuxFile *>(f);
+  return lf->get_fd();
+}
+
 constexpr size_t STDIN_BUFFER_SIZE = 512;
 char stdin_buffer[STDIN_BUFFER_SIZE];
 static LinuxFile StdIn(0, stdin_buffer, STDIN_BUFFER_SIZE, _IOFBF, false,

diff  --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 61ca8ce34bbba..f62b095997474 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -416,6 +416,18 @@ add_entrypoint_object(
     libc.src.stdio.printf_core.vfprintf_internal
 )
 
+add_entrypoint_object(
+  ftell
+  SRCS
+    ftell.cpp
+  HDRS
+    ftell.h
+  DEPENDS
+    libc.include.stdio
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+)
+
 add_entrypoint_object(
   remove
   ALIAS

diff  --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index 6facc969a2e5e..85f6de7595ce9 100644
--- a/libc/src/stdio/fopencookie.cpp
+++ b/libc/src/stdio/fopencookie.cpp
@@ -39,14 +39,18 @@ size_t read_func(File *f, void *data, size_t size) {
                                reinterpret_cast<char *>(data), size);
 }
 
-int seek_func(File *f, long offset, int whence) {
+long seek_func(File *f, long offset, int whence) {
   auto cookie_file = reinterpret_cast<CookieFile *>(f);
   if (cookie_file->ops.seek == nullptr) {
     errno = EINVAL;
     return -1;
   }
   off64_t offset64 = offset;
-  return cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
+  int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
+  if (result == 0)
+    return offset64;
+  else
+    return -1;
 }
 
 int close_func(File *f) {

diff  --git a/libc/src/stdio/ftell.cpp b/libc/src/stdio/ftell.cpp
new file mode 100644
index 0000000000000..40783ac58fca4
--- /dev/null
+++ b/libc/src/stdio/ftell.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of ftell -------------------------------------------===//
+//
+// 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/ftell.h"
+#include "src/__support/File/file.h"
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(long, ftell, (::FILE * stream)) {
+  return reinterpret_cast<__llvm_libc::File *>(stream)->tell();
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdio/ftell.h b/libc/src/stdio/ftell.h
new file mode 100644
index 0000000000000..95d4494709181
--- /dev/null
+++ b/libc/src/stdio/ftell.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of ftell --------------------------*- 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_FTELL_H
+#define LLVM_LIBC_SRC_STDIO_FTELL_H
+
+#include <stdio.h>
+
+namespace __llvm_libc {
+
+long ftell(::FILE *f);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_FTELL_H

diff  --git a/libc/test/src/__support/File/file_test.cpp b/libc/test/src/__support/File/file_test.cpp
index 271f2dce4ef55..bdf8de3639eb6 100644
--- a/libc/test/src/__support/File/file_test.cpp
+++ b/libc/test/src/__support/File/file_test.cpp
@@ -26,7 +26,7 @@ class StringFile : public __llvm_libc::File {
 
   static size_t str_read(__llvm_libc::File *f, void *data, size_t len);
   static size_t str_write(__llvm_libc::File *f, const void *data, size_t len);
-  static int str_seek(__llvm_libc::File *f, long offset, int whence);
+  static long str_seek(__llvm_libc::File *f, long offset, int whence);
   static int str_close(__llvm_libc::File *f) { return 0; }
   static int str_flush(__llvm_libc::File *f) { return 0; }
 
@@ -94,7 +94,7 @@ size_t StringFile::str_write(__llvm_libc::File *f, const void *data,
   return i;
 }
 
-int StringFile::str_seek(__llvm_libc::File *f, long offset, int whence) {
+long StringFile::str_seek(__llvm_libc::File *f, long offset, int whence) {
   StringFile *sf = static_cast<StringFile *>(f);
   if (whence == SEEK_SET)
     sf->pos = offset;
@@ -102,7 +102,7 @@ int StringFile::str_seek(__llvm_libc::File *f, long offset, int whence) {
     sf->pos += offset;
   if (whence == SEEK_END)
     sf->pos = SIZE + offset;
-  return 0;
+  return sf->pos;
 }
 
 StringFile *new_string_file(char *buffer, size_t buflen, int bufmode,

diff  --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index b453af2bb13c5..7c76c1990a685 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -235,6 +235,25 @@ add_libc_unittest(
     libc.src.stdio.fwrite
 )
 
+add_libc_unittest(
+  ftell_test
+  SUITE
+    libc_stdio_unittests
+  SRCS
+    ftell_test.cpp
+  DEPENDS
+    libc.include.errno
+    libc.include.stdio
+    libc.src.stdio.fclose
+    libc.src.stdio.fflush
+    libc.src.stdio.fopen
+    libc.src.stdio.fread
+    libc.src.stdio.fseek
+    libc.src.stdio.ftell
+    libc.src.stdio.fwrite
+    libc.src.stdio.setvbuf
+)
+
 add_subdirectory(printf_core)
 add_subdirectory(scanf_core)
 add_subdirectory(testdata)

diff  --git a/libc/test/src/stdio/ftell_test.cpp b/libc/test/src/stdio/ftell_test.cpp
new file mode 100644
index 0000000000000..a788c759300ea
--- /dev/null
+++ b/libc/test/src/stdio/ftell_test.cpp
@@ -0,0 +1,63 @@
+//===-- Unittests for ftell -----------------------------------------------===//
+//
+// 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/fclose.h"
+#include "src/stdio/fflush.h"
+#include "src/stdio/fopen.h"
+#include "src/stdio/fread.h"
+#include "src/stdio/fseek.h"
+#include "src/stdio/ftell.h"
+#include "src/stdio/fwrite.h"
+#include "src/stdio/setvbuf.h"
+#include "utils/UnitTest/Test.h"
+
+#include <stdio.h>
+
+class LlvmLibcFTellTest : public __llvm_libc::testing::Test {
+protected:
+  void test_with_bufmode(int bufmode) {
+    constexpr char FILENAME[] = "testdata/ftell.test";
+    // We will set a special buffer to the file so that we guarantee buffering.
+    constexpr size_t BUFFER_SIZE = 1024;
+    char buffer[BUFFER_SIZE];
+    ::FILE *file = __llvm_libc::fopen(FILENAME, "w+");
+    ASSERT_FALSE(file == nullptr);
+    ASSERT_EQ(__llvm_libc::setvbuf(file, buffer, bufmode, BUFFER_SIZE), 0);
+
+    // Include few '\n' chars to test when |bufmode| is _IOLBF.
+    constexpr char CONTENT[] = "12\n345\n6789";
+    constexpr size_t WRITE_SIZE = sizeof(CONTENT) - 1;
+    ASSERT_EQ(WRITE_SIZE, __llvm_libc::fwrite(CONTENT, 1, WRITE_SIZE, file));
+    // The above write should have buffered the written data and not have
+    // trasferred it to the underlying stream. But, ftell operation should
+    // still return the correct effective offset.
+    ASSERT_EQ(size_t(__llvm_libc::ftell(file)), WRITE_SIZE);
+
+    long offset = 5;
+    ASSERT_EQ(0, __llvm_libc::fseek(file, offset, SEEK_SET));
+    ASSERT_EQ(__llvm_libc::ftell(file), offset);
+    ASSERT_EQ(0, __llvm_libc::fseek(file, -offset, SEEK_END));
+    ASSERT_EQ(size_t(__llvm_libc::ftell(file)), size_t(WRITE_SIZE - offset));
+
+    ASSERT_EQ(0, __llvm_libc::fseek(file, 0, SEEK_SET));
+    constexpr size_t READ_SIZE = WRITE_SIZE / 2;
+    char data[READ_SIZE];
+    // Reading a small amount will actually read out much more data and
+    // buffer it. But, ftell should return the correct effective offset.
+    ASSERT_EQ(READ_SIZE, __llvm_libc::fread(data, 1, READ_SIZE, file));
+    ASSERT_EQ(size_t(__llvm_libc::ftell(file)), READ_SIZE);
+
+    ASSERT_EQ(0, __llvm_libc::fclose(file));
+  }
+};
+
+TEST_F(LlvmLibcFTellTest, TellWithFBF) { test_with_bufmode(_IOFBF); }
+
+TEST_F(LlvmLibcFTellTest, TellWithNBF) { test_with_bufmode(_IONBF); }
+
+TEST_F(LlvmLibcFTellTest, TellWithLBF) { test_with_bufmode(_IOLBF); }


        


More information about the libc-commits mailing list