Skip to content

Commit 0e89dc1

Browse files
committed
refactor(io): split file-handle.cpp into platform-specific files
Make the file-handle module easier to navigate and work with by splitting the .cpp into multiple files.
1 parent 4dbbfa2 commit 0e89dc1

File tree

3 files changed

+231
-196
lines changed

3 files changed

+231
-196
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ quick_lint_js_add_library(
159159
quick-lint-js/io/event-loop.h
160160
quick-lint-js/io/file-canonical.cpp
161161
quick-lint-js/io/file-canonical.h
162-
quick-lint-js/io/file-handle.cpp
162+
quick-lint-js/io/file-handle-posix.cpp
163+
quick-lint-js/io/file-handle-win32.cpp
163164
quick-lint-js/io/file-handle.h
164165
quick-lint-js/io/file-path.cpp
165166
quick-lint-js/io/file-path.h
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Copyright (C) 2020 Matthew "strager" Glazar
2+
// See end of file for extended copyright information.
3+
4+
#include <quick-lint-js/port/have.h>
5+
6+
#if QLJS_HAVE_UNISTD_H
7+
8+
#include <array>
9+
#include <cerrno>
10+
#include <cstddef>
11+
#include <cstdio>
12+
#include <cstring>
13+
#include <limits>
14+
#include <optional>
15+
#include <quick-lint-js/assert.h>
16+
#include <quick-lint-js/container/string-view.h>
17+
#include <quick-lint-js/io/file-handle.h>
18+
#include <quick-lint-js/io/pipe.h>
19+
#include <quick-lint-js/util/narrow-cast.h>
20+
#include <string>
21+
#include <string_view>
22+
#include <unistd.h>
23+
#include <utility>
24+
25+
#if QLJS_HAVE_FCNTL_H
26+
#include <fcntl.h>
27+
#endif
28+
29+
#if QLJS_HAVE_SYS_STAT_H
30+
#include <sys/stat.h>
31+
#endif
32+
33+
namespace quick_lint_js {
34+
bool posix_file_io_error::is_file_not_found_error() const noexcept {
35+
return this->error == ENOENT;
36+
}
37+
38+
std::string posix_file_io_error::to_string() const {
39+
return std::strerror(this->error);
40+
}
41+
42+
bool operator==(posix_file_io_error lhs, posix_file_io_error rhs) noexcept {
43+
return lhs.error == rhs.error;
44+
}
45+
46+
bool operator!=(posix_file_io_error lhs, posix_file_io_error rhs) noexcept {
47+
return !(lhs == rhs);
48+
}
49+
50+
posix_fd_file_ref::posix_fd_file_ref() noexcept
51+
: posix_fd_file_ref(this->invalid_fd) {}
52+
53+
posix_fd_file_ref::posix_fd_file_ref(int fd) noexcept : fd_(fd) {
54+
QLJS_ASSERT(this->fd_ >= 0 || this->fd_ == this->invalid_fd);
55+
}
56+
57+
bool posix_fd_file_ref::valid() const noexcept {
58+
return this->fd_ != this->invalid_fd;
59+
}
60+
61+
int posix_fd_file_ref::get() const noexcept { return this->fd_; }
62+
63+
file_read_result posix_fd_file_ref::read(void *buffer,
64+
int buffer_size) noexcept {
65+
QLJS_ASSERT(this->valid());
66+
::ssize_t read_size =
67+
::read(this->fd_, buffer, narrow_cast<std::size_t>(buffer_size));
68+
if (read_size == -1) {
69+
return failed_result(posix_file_io_error{errno});
70+
}
71+
return read_size == 0 ? file_read_result::end_of_file()
72+
: file_read_result(narrow_cast<int>(read_size));
73+
}
74+
75+
result<std::size_t, posix_file_io_error> posix_fd_file_ref::write(
76+
const void *buffer, std::size_t buffer_size) noexcept {
77+
QLJS_ASSERT(this->valid());
78+
::ssize_t written_size = ::write(this->fd_, buffer, buffer_size);
79+
if (written_size == -1) {
80+
return failed_result(posix_file_io_error{errno});
81+
}
82+
return narrow_cast<std::size_t>(written_size);
83+
}
84+
85+
result<void, posix_file_io_error> posix_fd_file_ref::write_full(
86+
const void *buffer, std::size_t buffer_size) noexcept {
87+
QLJS_ASSERT(this->valid());
88+
auto write_result = this->write(buffer, buffer_size);
89+
if (!write_result.ok()) {
90+
return write_result.propagate();
91+
}
92+
if (*write_result != buffer_size) {
93+
// TODO(strager): Should we retry with the remaining buffer?
94+
return failed_result(posix_file_io_error{EIO});
95+
}
96+
return {};
97+
}
98+
99+
bool posix_fd_file_ref::is_pipe_non_blocking() {
100+
QLJS_ASSERT(this->valid());
101+
#if QLJS_HAVE_FCNTL_H
102+
int rc = ::fcntl(this->get(), F_GETFL);
103+
if (rc == -1) {
104+
QLJS_UNIMPLEMENTED();
105+
}
106+
return (rc & O_NONBLOCK) != 0;
107+
#else
108+
#error "Unsupported platform"
109+
#endif
110+
}
111+
112+
#if !defined(__EMSCRIPTEN__)
113+
std::size_t posix_fd_file_ref::get_pipe_buffer_size() {
114+
QLJS_ASSERT(this->valid());
115+
#if QLJS_HAVE_F_GETPIPE_SZ
116+
int size = ::fcntl(this->fd_, F_GETPIPE_SZ);
117+
if (size == -1) {
118+
QLJS_UNIMPLEMENTED();
119+
}
120+
return narrow_cast<std::size_t>(size);
121+
#elif defined(__APPLE__)
122+
// See BIG_PIPE_SIZE in <xnu>/bsd/sys/pipe.h.
123+
return 65536;
124+
#elif QLJS_HAVE_PIPE
125+
#warning "Size returned by get_pipe_buffer_size might be inaccurate"
126+
pipe_fds pipe = make_pipe();
127+
pipe.writer.set_pipe_non_blocking();
128+
std::size_t pipe_buffer_size = 0;
129+
for (;;) {
130+
unsigned char c = 0;
131+
result<std::size_t, posix_file_io_error> written =
132+
pipe.writer.write(&c, sizeof(c));
133+
if (!written.ok()) {
134+
QLJS_ASSERT(written.error().error == EAGAIN);
135+
break;
136+
}
137+
pipe_buffer_size += *written;
138+
}
139+
return pipe_buffer_size;
140+
#else
141+
#error "Unknown platform"
142+
#endif
143+
}
144+
#endif
145+
146+
void posix_fd_file_ref::set_pipe_non_blocking() {
147+
QLJS_ASSERT(this->valid());
148+
#if QLJS_HAVE_FCNTL_H
149+
int rc = ::fcntl(this->get(), F_SETFL, O_NONBLOCK);
150+
if (rc != 0) {
151+
QLJS_UNIMPLEMENTED();
152+
}
153+
#else
154+
#error "Unsupported platform"
155+
#endif
156+
}
157+
158+
std::string posix_fd_file_ref::get_last_error_message() {
159+
return std::strerror(errno);
160+
}
161+
162+
posix_fd_file_ref posix_fd_file_ref::get_stdout() noexcept {
163+
return posix_fd_file_ref(STDOUT_FILENO);
164+
}
165+
166+
posix_fd_file_ref posix_fd_file_ref::get_stderr() noexcept {
167+
return posix_fd_file_ref(STDERR_FILENO);
168+
}
169+
170+
posix_fd_file::posix_fd_file() noexcept = default;
171+
172+
posix_fd_file::posix_fd_file(int fd) noexcept : posix_fd_file_ref(fd) {}
173+
174+
posix_fd_file::posix_fd_file(posix_fd_file &&other) noexcept
175+
: posix_fd_file_ref(std::exchange(other.fd_, this->invalid_fd)) {}
176+
177+
posix_fd_file &posix_fd_file::operator=(posix_fd_file &&other) noexcept {
178+
if (this != &other) {
179+
std::swap(this->fd_, other.fd_);
180+
if (other.valid()) {
181+
other.close();
182+
}
183+
}
184+
return *this;
185+
}
186+
187+
posix_fd_file::~posix_fd_file() {
188+
if (this->valid()) {
189+
this->close();
190+
}
191+
}
192+
193+
void posix_fd_file::close() {
194+
QLJS_ASSERT(this->valid());
195+
int rc = ::close(this->fd_);
196+
if (rc != 0) {
197+
std::fprintf(stderr, "error: failed to close file: %s\n",
198+
std::strerror(errno));
199+
}
200+
this->fd_ = invalid_fd;
201+
}
202+
203+
posix_fd_file_ref posix_fd_file::ref() const noexcept { return *this; }
204+
}
205+
206+
#endif
207+
208+
// quick-lint-js finds bugs in JavaScript programs.
209+
// Copyright (C) 2020 Matthew "strager" Glazar
210+
//
211+
// This file is part of quick-lint-js.
212+
//
213+
// quick-lint-js is free software: you can redistribute it and/or modify
214+
// it under the terms of the GNU General Public License as published by
215+
// the Free Software Foundation, either version 3 of the License, or
216+
// (at your option) any later version.
217+
//
218+
// quick-lint-js is distributed in the hope that it will be useful,
219+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
220+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
221+
// GNU General Public License for more details.
222+
//
223+
// You should have received a copy of the GNU General Public License
224+
// along with quick-lint-js. If not, see <https://www.gnu.org/licenses/>.

0 commit comments

Comments
 (0)