Working on backing files.
Also started a sketches project to illustrate quick ideas.
This commit is contained in:
parent
fd6e0c6899
commit
2dcc577f57
|
@ -1,7 +1,11 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<Objective-C>
|
||||
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
|
||||
<option name="INDENT_C_STRUCT_MEMBERS" value="8" />
|
||||
<option name="INDENT_CLASS_MEMBERS" value="8" />
|
||||
<option name="FUNCTION_BRACE_PLACEMENT" value="2" />
|
||||
<option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="2" />
|
||||
</Objective-C>
|
||||
<files>
|
||||
<extensions>
|
||||
|
@ -17,7 +21,16 @@
|
|||
</extensions>
|
||||
</files>
|
||||
<codeStyleSettings language="ObjectiveC">
|
||||
<option name="BLANK_LINES_BEFORE_IMPORTS" value="2" />
|
||||
<option name="BLANK_LINES_AFTER_IMPORTS" value="2" />
|
||||
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
|
||||
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
|
||||
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
|
||||
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="8" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#if ($HEADER_COMMENTS)
|
||||
///
|
||||
/// \file $FILE_NAME
|
||||
/// \author $USER_NAME
|
||||
/// \created $DATE
|
||||
/// \brief ${NAME} ...
|
||||
///
|
||||
#if ($ORGANIZATION_NAME && $ORGANIZATION_NAME != "")
|
||||
/// Copyright (c) $YEAR ${ORGANIZATION_NAME}#if (!$ORGANIZATION_NAME.endsWith(".")).#end All rights reserved.
|
||||
#else
|
||||
/// \section COPYRIGHT
|
||||
/// Copyright $YEAR K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
/// any purpose with or without fee is hereby granted, provided that the
|
||||
/// above copyright notice and this permission notice appear in all copies.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
/// SOFTWARE.
|
||||
#end
|
||||
///
|
||||
#end
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#parse("C File Header.h")
|
||||
#[[#ifndef]]# ${INCLUDE_GUARD}
|
||||
#[[#define]]# ${INCLUDE_GUARD}
|
||||
|
||||
${NAMESPACES_OPEN}
|
||||
|
||||
class ${NAME} {
|
||||
|
||||
};
|
||||
|
||||
${NAMESPACES_CLOSE}
|
||||
|
||||
#[[#endif]]# // ${INCLUDE_GUARD}
|
124
Buffer.cc
124
Buffer.cc
|
@ -20,12 +20,12 @@
|
|||
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
/// SOFTWARE.
|
||||
///
|
||||
/// @\section DESCRIPTION
|
||||
|
||||
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
#include "Buffer.h"
|
||||
|
||||
|
@ -34,9 +34,9 @@ static std::string
|
|||
anonymousName()
|
||||
{
|
||||
std::uniform_int_distribution<> dist(1000, 9999);
|
||||
std::random_device randomDevice;
|
||||
std::mt19937 rng(randomDevice());
|
||||
std::stringstream ss;
|
||||
std::random_device randomDevice;
|
||||
std::mt19937 rng(randomDevice());
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "Buffer<" << dist(rng) << ">";
|
||||
return ss.str();
|
||||
|
@ -44,35 +44,137 @@ anonymousName()
|
|||
|
||||
|
||||
Buffer::Buffer()
|
||||
: name(anonymousName())
|
||||
: dirty(false), name(anonymousName())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Buffer::Buffer(std::string fName)
|
||||
: name(std::move(fName))
|
||||
: dirty(false), name(std::move(fName))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
Buffer::Buffer(std::string fName, std::string fPath)
|
||||
: name(std::move(fName)), path(std::move(fPath))
|
||||
: dirty(false), name(std::move(fName)), path(fPath)
|
||||
{
|
||||
if (this->path) {
|
||||
this->file = OptFile(File(this->path.value()));
|
||||
this->file = OptFile (File(fPath));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Buffer::Flush(OptString altPath)
|
||||
Buffer::FileStatus
|
||||
Buffer::Flush(OptString altPath)
|
||||
{
|
||||
return altPath ? 0 : 1;
|
||||
OptOutFileStream handle = std::nullopt;
|
||||
|
||||
if (altPath) {
|
||||
auto altFile = File(altPath.value());
|
||||
handle = altFile.Flush();
|
||||
} else if (this->file) {
|
||||
handle = this->file.value().Flush();
|
||||
} else {
|
||||
// At this point, we have no alternate path to write out
|
||||
// and this Buffer isn't file-backed. From this point
|
||||
// forward, we can operate under the assumption that
|
||||
// `this->file` is a valid file.
|
||||
return Buffer::FileStatus::FileStatusVirtual;
|
||||
}
|
||||
|
||||
auto realFile = this->file.value();
|
||||
if (!handle) {
|
||||
if (realFile.IsReadOnly()) {
|
||||
return Buffer::FileStatus::FileStatusReadOnly;
|
||||
}
|
||||
|
||||
if (!realFile.IsWriteable()) {
|
||||
return Buffer::FileStatus::FileStatusInvalidPermissions;
|
||||
}
|
||||
|
||||
return Buffer::FileStatus::FileStatusIOFailed;
|
||||
}
|
||||
|
||||
/// At this point, we know we're working with a valid file handle.
|
||||
auto realHandle = handle.value();
|
||||
if (!realHandle->good()) {
|
||||
return Buffer::FileStatus::FileStatusIOFailed;
|
||||
}
|
||||
|
||||
for (auto line : this->contents) {
|
||||
std::copy(line.begin(), line.end(),
|
||||
std::ostream_iterator<uint8_t>(*realHandle, ""));
|
||||
}
|
||||
|
||||
realHandle->flush();
|
||||
realHandle->close();
|
||||
delete realHandle;
|
||||
this->dirty = false;
|
||||
return Buffer::FileStatus::FileStatusOK;
|
||||
}
|
||||
|
||||
|
||||
void Buffer::ChangePath(std::string newPath)
|
||||
Buffer::FileStatus
|
||||
Buffer::Refresh()
|
||||
{
|
||||
if (this->IsVirtual()) {
|
||||
return Buffer::FileStatus::FileStatusVirtual;
|
||||
}
|
||||
|
||||
auto realFile = this->file.value();
|
||||
auto handle = realFile.Refresh();
|
||||
if (!handle) {
|
||||
return FileStatus::FileStatusNonExistent;
|
||||
}
|
||||
|
||||
auto realHandle = handle.value();
|
||||
this->clearContents();
|
||||
this->dirty = false; // clean slate, kiddo
|
||||
|
||||
/// \todo Moral quandary: if the file disappears from disk, we
|
||||
/// probably want to know that, but maybe clearing the
|
||||
/// contents first isn't the right move.
|
||||
if (!realHandle->good()) {
|
||||
delete realHandle;
|
||||
return FileStatus::FileStatusIOFailed;
|
||||
}
|
||||
|
||||
size_t currentLine = 0;
|
||||
|
||||
while (realHandle->good()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Buffer::ChangePath(std::string newPath)
|
||||
{
|
||||
this->path = OptString(std::move(newPath));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Buffer::clearContents()
|
||||
{
|
||||
for (auto & line : this->contents) {
|
||||
line.clear();
|
||||
}
|
||||
|
||||
this->contents.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Buffer::MarkDirty()
|
||||
{
|
||||
if (this->dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->dirty = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
74
Buffer.h
74
Buffer.h
|
@ -17,7 +17,7 @@
|
|||
#include "Cursor.h"
|
||||
|
||||
|
||||
typedef std::vector<std::vector<uint8_t>> BufferContents;
|
||||
typedef std::vector<std::vector<uint8_t>> BufferContents;
|
||||
|
||||
|
||||
/// A Buffer is the atom of text editing. It represents a single document,
|
||||
|
@ -32,6 +32,38 @@ typedef std::vector<std::vector<uint8_t>> BufferContents;
|
|||
/// cannot be demoted to a virtual buffer.
|
||||
class Buffer {
|
||||
public:
|
||||
enum class FileStatus : uint8_t {
|
||||
/// The file operation succeeded correctly.
|
||||
FileStatusOK = 0,
|
||||
|
||||
/// The file can't be written to because it is marked
|
||||
/// read-only. This refers to a buffer being marked as
|
||||
/// read-only, not to whether the underlying file is
|
||||
/// actually read-only.
|
||||
FileStatusReadOnly = 1,
|
||||
|
||||
/// There was an I/O error trying to write to the file.
|
||||
FileStatusIOFailed = 2,
|
||||
|
||||
/// The Buffer couldn't be flushed because it is a virtual
|
||||
/// buffer. If the user explicitly tried to save the buffer,
|
||||
/// they should be prompted for a path.
|
||||
FileStatusVirtual = 3,
|
||||
|
||||
/// The underlying file doesn't have the right permissions;
|
||||
/// for example, it's not writeable if the user is trying to
|
||||
/// write the file.
|
||||
FileStatusInvalidPermissions = 4,
|
||||
|
||||
/// The underlying file doesn't exist.
|
||||
FileStatusNonExistent = 5,
|
||||
};
|
||||
|
||||
|
||||
static bool StatusOK(FileStatus status)
|
||||
{ return status == FileStatus::FileStatusOK; }
|
||||
|
||||
|
||||
/// The constructor with no arguments generates a new anonymous
|
||||
/// buffer.
|
||||
Buffer();
|
||||
|
@ -42,18 +74,42 @@ public:
|
|||
/// Instantiate a Buffer pointing to fPath.
|
||||
Buffer(std::string fName, std::string fPath);
|
||||
|
||||
std::string Name() const { return this->name; }
|
||||
std::string Name() const
|
||||
{ return this->name; }
|
||||
|
||||
int Flush(OptString altPath);
|
||||
void ChangePath(std::string newPath);
|
||||
bool IsVirtual()
|
||||
{ return this->file.has_value(); }
|
||||
|
||||
Buffer::FileStatus Flush(OptString altPath);
|
||||
|
||||
/// Refresh reads the contents of the file back into the
|
||||
/// buffer.
|
||||
///
|
||||
/// \warning This does not care if the file is dirty or not -
|
||||
/// it WILL overwrite the contents of the buffer.
|
||||
///
|
||||
/// \return A FileStatus indicating whether the read was successful.
|
||||
Buffer::FileStatus Refresh();
|
||||
|
||||
void ChangePath(std::string newPath);
|
||||
|
||||
Cursor Cursor()
|
||||
{ return this->cursor; }
|
||||
|
||||
void MarkDirty();
|
||||
bool IsDirty()
|
||||
{ return this->dirty; }
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
OptString path;
|
||||
OptFile file;
|
||||
Cursor cursor;
|
||||
BufferContents contents;
|
||||
void clearContents();
|
||||
|
||||
class Cursor cursor;
|
||||
|
||||
bool dirty;
|
||||
std::string name;
|
||||
OptString path;
|
||||
OptFile file;
|
||||
BufferContents contents;
|
||||
};
|
||||
|
||||
|
||||
|
|
12
Defs.h
12
Defs.h
|
@ -28,8 +28,13 @@
|
|||
#include <string>
|
||||
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
|
||||
typedef std::optional<std::string> OptString;
|
||||
|
||||
|
||||
template<typename T>
|
||||
T Min(T a, T b) { return a > b ? b : a; }
|
||||
template size_t Min<size_t>(size_t a, size_t b);
|
||||
|
@ -39,4 +44,11 @@ T Max(T a, T b) { return a > b ? a : b; }
|
|||
template size_t Max(size_t a, size_t b);
|
||||
|
||||
|
||||
/// \todo Consider abstracting platforms to a separate subsystem.
|
||||
static const std::string PlatformLinux("Linux");
|
||||
static const std::string PlatformApple("Darwin");
|
||||
static const std::string PlatformWindows("Windows");
|
||||
static const std::string PlatformCurrent(TOSTRING(KGE_PLATFORM));
|
||||
|
||||
|
||||
#endif // KEPP__DEFS_H_
|
||||
|
|
85
File.cc
85
File.cc
|
@ -21,12 +21,13 @@
|
|||
/// SOFTWARE.
|
||||
///
|
||||
|
||||
#include <filesystem>
|
||||
#include "File.h"
|
||||
|
||||
|
||||
const std::string &File::Path() const
|
||||
const std::string File::Path()
|
||||
{
|
||||
return path;
|
||||
return this->path.string();
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,3 +42,83 @@ File::File(std::string fPath)
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
OptOutFileStream File::Flush()
|
||||
{
|
||||
// Exit early if we shouldn't be writing to the file.
|
||||
if (this->IsReadOnly()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!this->Exists()) {
|
||||
if (!this->IsWriteable()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return {new std::ofstream(this->path, this->mode|std::ios::trunc)};
|
||||
}
|
||||
|
||||
return {new std::ofstream(this->path, this->mode)};
|
||||
}
|
||||
|
||||
|
||||
OptInFileStream
|
||||
File::Refresh()
|
||||
{
|
||||
if (!this->Exists()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return {new std::ifstream(this->path, this->mode)};
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
File::Size()
|
||||
{
|
||||
return std::filesystem::file_size(this->path);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
File::Exists()
|
||||
{
|
||||
return std::filesystem::exists(this->path);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
checkAccess(std::filesystem::path path, std::filesystem::perms mode, bool checkParent)
|
||||
{
|
||||
if (!std::filesystem::exists(path) && checkParent) {
|
||||
auto fullPath = std::filesystem::absolute(path);
|
||||
auto parent = fullPath.parent_path();
|
||||
auto dirEnt = std::filesystem::directory_entry(parent);
|
||||
auto perms = dirEnt.status().permissions();
|
||||
return (perms & mode) != std::filesystem::perms::none;
|
||||
}
|
||||
|
||||
return (status(path).permissions() & mode) != std::filesystem::perms::none;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
File::IsWriteable()
|
||||
{
|
||||
return checkAccess(this->path, std::filesystem::perms::owner_write, true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
File::IsReadable()
|
||||
{
|
||||
return checkAccess(this->path, std::filesystem::perms::owner_read, false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
File::IsReadWriteable()
|
||||
{
|
||||
auto checkMode = std::filesystem::perms::owner_read | std::filesystem::perms::owner_write;
|
||||
return checkAccess(this->path, checkMode, true);
|
||||
}
|
||||
|
|
36
File.h
36
File.h
|
@ -25,6 +25,7 @@
|
|||
#define KEPP__FILE_H_
|
||||
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <string>
|
||||
|
@ -32,6 +33,12 @@
|
|||
#include "Defs.h"
|
||||
|
||||
|
||||
typedef std::optional<std::ofstream *> OptOutFileStream;
|
||||
typedef std::optional<std::ifstream *> OptInFileStream;
|
||||
|
||||
|
||||
|
||||
/// Files default to being read/write.
|
||||
static constexpr std::ios::openmode DefaultMode =
|
||||
std::ios::in|std::ios::out;
|
||||
|
||||
|
@ -41,18 +48,41 @@ class File {
|
|||
public:
|
||||
File(std::string fPath);
|
||||
|
||||
const std::string &Path() const;
|
||||
const std::string Path();
|
||||
void SetPath(const std::string &fPath);
|
||||
|
||||
// int Refresh(std::);
|
||||
|
||||
OptOutFileStream Flush();
|
||||
OptInFileStream Refresh();
|
||||
|
||||
/// The readonly attribute on a File is a virtual write
|
||||
/// protection, and does not reflect the permissions on
|
||||
/// the file itself. For that, see IsWriteable.
|
||||
[[nodiscard]] bool IsReadOnly() const { return this->readOnly; };
|
||||
void MarkReadOnly() { this->readOnly = true; }
|
||||
void ClearReadOnly() { this->readOnly = false; }
|
||||
|
||||
/// Size returns the size of the file on disk.
|
||||
size_t Size();
|
||||
|
||||
/// Exists checks whether the file exists on disk.
|
||||
bool Exists();
|
||||
|
||||
/// IsWriteable checks whether the current user has write
|
||||
/// permissions for the file.
|
||||
bool IsWriteable();
|
||||
|
||||
/// IsReadable checks whether the current user has read
|
||||
/// permissions on the file.
|
||||
bool IsReadable();
|
||||
|
||||
/// IsReadWriteable checks whether the current user has both
|
||||
/// read and write permissions on the file.
|
||||
bool IsReadWriteable();
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
|
||||
std::filesystem::path path;
|
||||
bool readOnly;
|
||||
std::ios::openmode mode;
|
||||
};
|
||||
|
|
10
main.cc
10
main.cc
|
@ -26,12 +26,14 @@
|
|||
|
||||
#include "Buffer.h"
|
||||
#include "Cursor.h"
|
||||
#include "LineEnding.h"
|
||||
|
||||
|
||||
static void
|
||||
usage(std::ostream &os, int exitCode)
|
||||
{
|
||||
os << "ke - kyle's editor ++\n";
|
||||
os << "ke - kyle's editor version " << TOSTRING(KGE_VERSION)
|
||||
<< "/" << PlatformCurrent << "\n";
|
||||
os << "\nUsage:\n";
|
||||
os << "\tke [files]\n";
|
||||
exit(exitCode);
|
||||
|
@ -46,18 +48,16 @@ ShowDist(Cursor a, Cursor b)
|
|||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
if ((argc == 2) && (std::string(argv[1]) == "-h")) {
|
||||
std::cout << "help?\n";
|
||||
usage(std::cout, 0);
|
||||
}
|
||||
|
||||
Buffer frame;
|
||||
std::cout << frame.Name() << "\n";
|
||||
|
||||
ShowDist(Cursor(0, 0), Cursor(5, 5));
|
||||
ShowDist(Cursor(2, 2), Cursor(4, 4));
|
||||
ShowDist(Cursor(32, 12), Cursor(14, 71));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
project(ke_sketches
|
||||
DESCRIPTION "sketches and small test programs for kyle's editor"
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.1)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_VERBOSE_MAKEFILES TRUE)
|
||||
set(VERBOSE YES)
|
||||
|
||||
if (MSVC)
|
||||
add_compile_options("/W4" "$<$<CONFIG:RELEASE>:/O2>")
|
||||
else ()
|
||||
add_compile_options(
|
||||
"-Wall"
|
||||
"-Wextra"
|
||||
"-Werror"
|
||||
"-static"
|
||||
"$<$<CONFIG:DEBUG>:-g>"
|
||||
"$<$<CONFIG:RELEASE>:-O2>")
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options(
|
||||
"-stdlib=libc++"
|
||||
"-fsanitize=address"
|
||||
"-fno-omit-frame-pointer"
|
||||
"-fsanitize-address-use-after-scope"
|
||||
)
|
||||
else ()
|
||||
# nothing special for gcc at the moment
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
add_executable(readFile ReadFile.cc)
|
||||
add_executable(enoent enoent.cc)
|
|
@ -0,0 +1,87 @@
|
|||
///
|
||||
/// \file ReadFile.cc
|
||||
/// \author kyle
|
||||
/// \created 2023-10-11
|
||||
/// \brief ReadFile tests reading a file.
|
||||
///
|
||||
/// \section COPYRIGHT
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
/// any purpose with or without fee is hereby granted, provided that the
|
||||
/// above copyright notice and this permission notice appear in all copies.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
/// SOFTWARE.
|
||||
///
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
int
|
||||
readFile(const std::string path)
|
||||
{
|
||||
std::cout << "[+] opening " << path << "\n";
|
||||
std::ifstream input(path, std::ios::in);
|
||||
|
||||
if (!input.good()) {
|
||||
std::cerr << "[!] failed to open " << path << "\n";
|
||||
input.close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "[+] reading from " << path << "\n";
|
||||
std::vector<std::vector<uint8_t>> doc;
|
||||
while (input.good()) {
|
||||
std::string temp;
|
||||
while (std::getline(input, temp)) {
|
||||
std::cout << "[+] line: " << temp << "\n";
|
||||
std::vector<uint8_t> row(temp.begin(), temp.end());
|
||||
doc.push_back(row);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "[+] finished reading document\n";
|
||||
std::cout << "\tgood: " << input.good() << "\n";
|
||||
std::cout << "\tfail: " << input.fail() << "\n";
|
||||
std::cout << "\t bad: " << input.bad() << "\n";
|
||||
std::cout << "\t eof: " << input.eof() << "\n";
|
||||
|
||||
input.close();
|
||||
|
||||
std::cout << "[+] dumping document of " << doc.size() << " lines.\n";
|
||||
for (size_t i = 0; i < doc.size(); i++) {
|
||||
std::cout << "line " << std::setw(3) << i << ": ";
|
||||
std::copy(doc[i].begin(), doc[i].end(),
|
||||
std::ostream_iterator<uint8_t>(std::cout, ""));
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::cout << "[+] input file: " << argv[i] << "\n";
|
||||
if (readFile(std::string(argv[i])) != 0) {
|
||||
std::cerr << "[!] failed\n";
|
||||
} else {
|
||||
std::cout << "[+] OK\n";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
///
|
||||
/// \file enoent.cc
|
||||
/// \author kyle
|
||||
/// \created 2023-10-11
|
||||
/// \brief basic file system checks
|
||||
///
|
||||
/// \section COPYRIGHT
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
/// any purpose with or without fee is hereby granted, provided that the
|
||||
/// above copyright notice and this permission notice appear in all copies.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
/// SOFTWARE.
|
||||
///
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string input = "ohai\n";
|
||||
std::vector<uint8_t> buffer(input.begin(), input.end());
|
||||
auto f = fs::path("ENOENT2");
|
||||
|
||||
if (fs::exists(f)) {
|
||||
std::cout << "[+] the file exists\n";
|
||||
std::cout << "\tfile size: " << fs::file_size(f) << "\n";
|
||||
} else {
|
||||
std::cout << "the file does not exist\n";
|
||||
}
|
||||
cout << "[+] attempting to open the file.\n";
|
||||
ofstream handle(f, std::ios::in | std::ios::out | std::ios::trunc);
|
||||
|
||||
if (!handle.good()) {
|
||||
cerr << "[!] file operation failed\n";
|
||||
cerr << "\tfile fail: " << handle.fail() << "\n";
|
||||
cerr << "\t file eof: " << handle.eof() << "\n";
|
||||
cerr << "\t file bad: " << handle.bad() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fs::exists(f)) {
|
||||
std::cout << "[+] the file exists\n";
|
||||
std::cout << "\tfile size: " << fs::file_size(f) << "\n";
|
||||
} else {
|
||||
std::cout << "the file does not exist\n";
|
||||
}
|
||||
handle.flush();
|
||||
if (fs::exists(f)) {
|
||||
std::cout << "[+] the file exists\n";
|
||||
std::cout << "\tfile size: " << fs::file_size(f) << "\n";
|
||||
} else {
|
||||
std::cout << "the file does not exist\n";
|
||||
}
|
||||
cout << "[+] file open successfully. attempting to write.\n";
|
||||
handle << "Hello, world.\r\n";
|
||||
|
||||
if (fs::exists(f)) {
|
||||
std::cout << "\tfile size: " << fs::file_size(f) << "\n";
|
||||
}
|
||||
|
||||
cout << "[+] attempting to write the vector to file.\n";
|
||||
|
||||
std::copy(buffer.begin(), buffer.end(), std::ostream_iterator<uint8_t>(handle, ""));
|
||||
|
||||
cout << "[+] closing the file.\n";
|
||||
handle.close();
|
||||
|
||||
if (fs::exists(f)) {
|
||||
std::cout << "\tfile size: " << fs::file_size(f) << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
this is a short text file.
|
||||
|
||||
just wanted to see what it looks like.
|
||||
|
||||
of course
|
||||
|
||||
of course. This is more of a paragraph that should end |
|
||||
at the pipes, which should be a border. It's one way to|
|
||||
test it's being read correctly.
|
Loading…
Reference in New Issue