Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorSiva Chandra Reddy <sivachandra@google.com>2022-11-04 08:42:49 +0300
committerSiva Chandra Reddy <sivachandra@google.com>2022-11-08 00:38:53 +0300
commit43e52ad553cbafb78386e9e6e1204c8de8a506d4 (patch)
treeddb043484f2d4229f5336b8017d1a805be23a155 /libc
parentd8233b5b4f4394b6d8fd969cb786bd702982f5cb (diff)
[libc] Add implementations of ftell.
Reviewed By: michaelrj, lntue Differential Revision: https://reviews.llvm.org/D137395
Diffstat (limited to 'libc')
-rw-r--r--libc/config/linux/x86_64/entrypoints.txt1
-rw-r--r--libc/include/CMakeLists.txt1
-rw-r--r--libc/spec/stdc.td5
-rw-r--r--libc/src/__support/File/file.cpp23
-rw-r--r--libc/src/__support/File/file.h10
-rw-r--r--libc/src/__support/File/linux_file.cpp13
-rw-r--r--libc/src/stdio/CMakeLists.txt12
-rw-r--r--libc/src/stdio/fopencookie.cpp8
-rw-r--r--libc/src/stdio/ftell.cpp20
-rw-r--r--libc/src/stdio/ftell.h20
-rw-r--r--libc/test/src/__support/File/file_test.cpp6
-rw-r--r--libc/test/src/stdio/CMakeLists.txt19
-rw-r--r--libc/test/src/stdio/ftell_test.cpp63
13 files changed, 191 insertions, 10 deletions
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 2c4867f48b1b..8349af0e54e2 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 ac4e57572a69..f9d3ee5164f9 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 64ee9b7c4539..bb3f9a1c701b 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -564,6 +564,11 @@ def StdC : StandardSpec<"stdc"> {
ArgSpec<FILEPtr>]
>,
FunctionSpec<
+ "ftell",
+ RetValSpec<LongType>,
+ [ArgSpec<FILEPtr>]
+ >,
+ FunctionSpec<
"putc",
RetValSpec<IntType>,
[ArgSpec<IntType>,
diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index 9129f68b521d..edb2467929f2 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 e08508bcb1d8..d182ea4c81b4 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -28,7 +28,9 @@ public:
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 @@ public:
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 @@ private:
// 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 c6c93c8ef508..09a880743baf 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 61ca8ce34bbb..f62b09599747 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -417,6 +417,18 @@ add_entrypoint_object(
)
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
DEPENDS
diff --git a/libc/src/stdio/fopencookie.cpp b/libc/src/stdio/fopencookie.cpp
index 6facc969a2e5..85f6de7595ce 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 000000000000..40783ac58fca
--- /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 000000000000..95d449470918
--- /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 271f2dce4ef5..bdf8de3639eb 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 b453af2bb13c..7c76c1990a68 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 000000000000..a788c759300e
--- /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); }