Skip to content

Commit

Permalink
Move posix_fd_file, etc. into their own file
Browse files Browse the repository at this point in the history
I want to use posix_fd_file outside of file.cpp. Move the posix_fd_file
class (and the related windows_handle_file class) into its own module so
it can be reused.

This commit should not change behavior.
  • Loading branch information
strager committed Sep 26, 2020
1 parent 16a2d25 commit 4bcd7dd
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 117 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -35,6 +35,7 @@ quick_lint_js_add_library(
assert.cpp
char8.cpp
error.cpp
file-handle.cpp
file.cpp
integer.cpp
language.cpp
Expand Down
138 changes: 138 additions & 0 deletions src/file-handle.cpp
@@ -0,0 +1,138 @@
// quick-lint-js finds bugs in JavaScript programs.
// Copyright (C) 2020 Matthew Glazar
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <limits>
#include <optional>
#include <quick-lint-js/file-handle.h>
#include <quick-lint-js/have.h>
#include <quick-lint-js/narrow-cast.h>
#include <string>
#include <string_view>

#if QLJS_HAVE_FCNTL_H
#include <fcntl.h>
#endif

#if QLJS_HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#if QLJS_HAVE_UNISTD_H
#include <unistd.h>
#endif

#if QLJS_HAVE_WINDOWS_H
#include <Windows.h>
#endif

namespace quick_lint_js {
#if QLJS_HAVE_WINDOWS_H
windows_handle_file::windows_handle_file(HANDLE handle) noexcept
: handle_(handle) {}

windows_handle_file::~windows_handle_file() {
if (!::CloseHandle(this->handle_)) {
std::fprintf(stderr, "error: failed to close file\n");
}
}

HANDLE windows_handle_file::get() noexcept { return this->handle_; }

std::optional<int> windows_handle_file::read(void *buffer,
int buffer_size) noexcept {
DWORD read_size;
if (!::ReadFile(this->handle_, buffer, narrow_cast<DWORD>(buffer_size),
&read_size,
/*lpOverlapped=*/nullptr)) {
return std::nullopt;
}
return narrow_cast<int>(read_size);
}

std::string windows_handle_file::get_last_error_message() {
return windows_error_message(::GetLastError());
}
#endif

#if QLJS_HAVE_UNISTD_H
posix_fd_file::posix_fd_file(int fd) noexcept : fd_(fd) {}

posix_fd_file::~posix_fd_file() {
int rc = ::close(this->fd_);
if (rc != 0) {
std::fprintf(stderr, "error: failed to close file: %s\n",
std::strerror(errno));
}
}

int posix_fd_file::get() noexcept { return this->fd_; }

std::optional<int> posix_fd_file::read(void *buffer, int buffer_size) noexcept {
::ssize_t read_size =
::read(this->fd_, buffer, narrow_cast<std::size_t>(buffer_size));
if (read_size == -1) {
return std::nullopt;
}
return narrow_cast<int>(read_size);
}

std::string posix_fd_file::get_last_error_message() {
return std::strerror(errno);
}
#endif

#if QLJS_HAVE_WINDOWS_H
namespace {
std::string_view remove_suffix_if_present(std::string_view s,
std::string_view suffix) noexcept {
if (s.ends_with(suffix)) {
s.remove_suffix(suffix.size());
}
return s;
}
}

std::string windows_error_message(DWORD error) {
// TODO(strager): Use FormatMessageW.
LPSTR get_last_error_message;
DWORD get_last_error_message_length = ::FormatMessageA(
/*dwFlags=*/FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
/*lpSource=*/nullptr,
/*dwMessageId=*/::GetLastError(),
/*dwLanguageId=*/0,
/*lpBuffer=*/reinterpret_cast<LPSTR>(&get_last_error_message),
/*nSize=*/(std::numeric_limits<DWORD>::max)(),
/*Arguments=*/nullptr);
if (get_last_error_message_length == 0) {
// FormatMessageA failed.
return "unknown error";
}

std::string_view message(
get_last_error_message,
narrow_cast<std::size_t>(get_last_error_message_length));
message = remove_suffix_if_present(message, "\r\n");
std::string message_copy(message);
static_cast<void>(::LocalFree(get_last_error_message));
return message_copy;
}
#endif
}
114 changes: 1 addition & 113 deletions src/file.cpp
Expand Up @@ -19,16 +19,14 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <optional>
#include <quick-lint-js/assert.h>
#include <quick-lint-js/char8.h>
#include <quick-lint-js/file-handle.h>
#include <quick-lint-js/file.h>
#include <quick-lint-js/have.h>
#include <quick-lint-js/narrow-cast.h>
#include <quick-lint-js/warning.h>
#include <string>
#include <string_view>

#if QLJS_HAVE_FCNTL_H
#include <fcntl.h>
Expand All @@ -38,10 +36,6 @@
#include <sys/stat.h>
#endif

#if QLJS_HAVE_UNISTD_H
#include <unistd.h>
#endif

#if QLJS_HAVE_WINDOWS_H
#include <Windows.h>
#endif
Expand Down Expand Up @@ -70,77 +64,9 @@ read_file_result read_file_result::failure(const std::string &error) {

namespace {
#if defined(QLJS_FILE_WINDOWS)
std::string windows_error_message(DWORD error);
#endif

#if defined(QLJS_FILE_WINDOWS)
class windows_handle_file {
public:
explicit windows_handle_file(HANDLE handle) noexcept : handle_(handle) {}

windows_handle_file(const windows_handle_file &) = delete;
windows_handle_file &operator=(const windows_handle_file &) = delete;

~windows_handle_file() {
if (!::CloseHandle(this->handle_)) {
std::fprintf(stderr, "error: failed to close file\n");
}
}

HANDLE get() noexcept { return this->handle_; }

std::optional<int> read(void *buffer, int buffer_size) noexcept {
DWORD read_size;
if (!::ReadFile(this->handle_, buffer, narrow_cast<DWORD>(buffer_size),
&read_size,
/*lpOverlapped=*/nullptr)) {
return std::nullopt;
}
return narrow_cast<int>(read_size);
}

static std::string get_last_error_message() {
return windows_error_message(::GetLastError());
}

private:
HANDLE handle_;
};
using platform_file = windows_handle_file;
#endif

#if defined(QLJS_FILE_POSIX)
class posix_fd_file {
public:
explicit posix_fd_file(int fd) noexcept : fd_(fd) {}

posix_fd_file(const posix_fd_file &) = delete;
posix_fd_file &operator=(const posix_fd_file &) = delete;

~posix_fd_file() {
int rc = ::close(this->fd_);
if (rc != 0) {
std::fprintf(stderr, "error: failed to close file: %s\n",
std::strerror(errno));
}
}

int get() noexcept { return this->fd_; }

std::optional<int> read(void *buffer, int buffer_size) noexcept {
::ssize_t read_size =
::read(this->fd_, buffer, narrow_cast<std::size_t>(buffer_size));
if (read_size == -1) {
return std::nullopt;
}
return narrow_cast<int>(read_size);
}

static std::string get_last_error_message() { return std::strerror(errno); }

private:
int fd_;
};
using platform_file = posix_fd_file;
#endif

Expand Down Expand Up @@ -259,42 +185,4 @@ read_file_result read_file(const char *path) {
return read_file(path, file);
}
#endif

namespace {
#if defined(QLJS_FILE_WINDOWS)
std::string_view remove_suffix_if_present(std::string_view s,
std::string_view suffix) noexcept {
if (s.ends_with(suffix)) {
s.remove_suffix(suffix.size());
}
return s;
}

std::string windows_error_message(DWORD error) {
// TODO(strager): Use FormatMessageW.
LPSTR get_last_error_message;
DWORD get_last_error_message_length = ::FormatMessageA(
/*dwFlags=*/FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
/*lpSource=*/nullptr,
/*dwMessageId=*/::GetLastError(),
/*dwLanguageId=*/0,
/*lpBuffer=*/reinterpret_cast<LPSTR>(&get_last_error_message),
/*nSize=*/(std::numeric_limits<DWORD>::max)(),
/*Arguments=*/nullptr);
if (get_last_error_message_length == 0) {
// FormatMessageA failed.
return "unknown error";
}

std::string_view message(
get_last_error_message,
narrow_cast<std::size_t>(get_last_error_message_length));
message = remove_suffix_if_present(message, "\r\n");
std::string message_copy(message);
static_cast<void>(::LocalFree(get_last_error_message));
return message_copy;
}
#endif
}
}
71 changes: 71 additions & 0 deletions src/include/quick-lint-js/file-handle.h
@@ -0,0 +1,71 @@
// quick-lint-js finds bugs in JavaScript programs.
// Copyright (C) 2020 Matthew Glazar
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#include <optional>
#include <quick-lint-js/have.h>
#include <string>

#if QLJS_HAVE_WINDOWS_H
#include <Windows.h>
#endif

namespace quick_lint_js {
#if QLJS_HAVE_WINDOWS_H
std::string windows_error_message(DWORD error);
#endif

#if QLJS_HAVE_WINDOWS_H
class windows_handle_file {
public:
explicit windows_handle_file(HANDLE) noexcept;

windows_handle_file(const windows_handle_file &) = delete;
windows_handle_file &operator=(const windows_handle_file &) = delete;

~windows_handle_file();

HANDLE get() noexcept;

std::optional<int> read(void *buffer, int buffer_size) noexcept;

static std::string get_last_error_message();

private:
HANDLE handle_;
};
#endif

#if QLJS_HAVE_UNISTD_H
class posix_fd_file {
public:
explicit posix_fd_file(int fd) noexcept;

posix_fd_file(const posix_fd_file &) = delete;
posix_fd_file &operator=(const posix_fd_file &) = delete;

~posix_fd_file();

int get() noexcept;

std::optional<int> read(void *buffer, int buffer_size) noexcept;

static std::string get_last_error_message();

private:
int fd_;
};
#endif
}
8 changes: 4 additions & 4 deletions src/include/quick-lint-js/narrow-cast.h
Expand Up @@ -30,13 +30,13 @@ constexpr bool can_narrow_cast([[maybe_unused]] In x) noexcept {
if constexpr (std::is_same_v<In, Out>) {
return true;
} else if constexpr (std::is_signed_v<In> && std::is_signed_v<Out>) {
return out_limits::lowest() <= x && x <= out_limits::max();
return out_limits::lowest() <= x && x <= (out_limits::max)();
} else if constexpr (std::is_signed_v<In> && !std::is_signed_v<Out>) {
return 0 <= x && static_cast<unsigned_in>(x) <= out_limits::max();
return 0 <= x && static_cast<unsigned_in>(x) <= (out_limits::max)();
} else if constexpr (!std::is_signed_v<In> && std::is_signed_v<Out>) {
return x <= unsigned_out{out_limits::max()};
return x <= unsigned_out{(out_limits::max)()};
} else if constexpr (!std::is_signed_v<In> && !std::is_signed_v<Out>) {
return x <= out_limits::max();
return x <= (out_limits::max)();
}
}

Expand Down

0 comments on commit 4bcd7dd

Please sign in to comment.