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">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<Objective-C>
|
<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_BRACE_PLACEMENT" value="2" />
|
||||||
|
<option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="2" />
|
||||||
</Objective-C>
|
</Objective-C>
|
||||||
<files>
|
<files>
|
||||||
<extensions>
|
<extensions>
|
||||||
|
@ -17,7 +21,16 @@
|
||||||
</extensions>
|
</extensions>
|
||||||
</files>
|
</files>
|
||||||
<codeStyleSettings language="ObjectiveC">
|
<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="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>
|
<indentOptions>
|
||||||
<option name="INDENT_SIZE" value="8" />
|
<option name="INDENT_SIZE" value="8" />
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<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
|
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
/// SOFTWARE.
|
/// SOFTWARE.
|
||||||
///
|
///
|
||||||
/// @\section DESCRIPTION
|
|
||||||
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ static std::string
|
||||||
anonymousName()
|
anonymousName()
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<> dist(1000, 9999);
|
std::uniform_int_distribution<> dist(1000, 9999);
|
||||||
std::random_device randomDevice;
|
std::random_device randomDevice;
|
||||||
std::mt19937 rng(randomDevice());
|
std::mt19937 rng(randomDevice());
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << "Buffer<" << dist(rng) << ">";
|
ss << "Buffer<" << dist(rng) << ">";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
@ -44,35 +44,137 @@ anonymousName()
|
||||||
|
|
||||||
|
|
||||||
Buffer::Buffer()
|
Buffer::Buffer()
|
||||||
: name(anonymousName())
|
: dirty(false), name(anonymousName())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Buffer::Buffer(std::string fName)
|
Buffer::Buffer(std::string fName)
|
||||||
: name(std::move(fName))
|
: dirty(false), name(std::move(fName))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Buffer::Buffer(std::string fName, std::string fPath)
|
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) {
|
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));
|
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"
|
#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,
|
/// 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.
|
/// cannot be demoted to a virtual buffer.
|
||||||
class Buffer {
|
class Buffer {
|
||||||
public:
|
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
|
/// The constructor with no arguments generates a new anonymous
|
||||||
/// buffer.
|
/// buffer.
|
||||||
Buffer();
|
Buffer();
|
||||||
|
@ -42,18 +74,42 @@ public:
|
||||||
/// Instantiate a Buffer pointing to fPath.
|
/// Instantiate a Buffer pointing to fPath.
|
||||||
Buffer(std::string fName, std::string 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);
|
bool IsVirtual()
|
||||||
void ChangePath(std::string newPath);
|
{ 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:
|
private:
|
||||||
std::string name;
|
void clearContents();
|
||||||
OptString path;
|
|
||||||
OptFile file;
|
class Cursor cursor;
|
||||||
Cursor cursor;
|
|
||||||
BufferContents contents;
|
bool dirty;
|
||||||
|
std::string name;
|
||||||
|
OptString path;
|
||||||
|
OptFile file;
|
||||||
|
BufferContents contents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
12
Defs.h
12
Defs.h
|
@ -28,8 +28,13 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
#define STRINGIFY(x) #x
|
||||||
|
#define TOSTRING(x) STRINGIFY(x)
|
||||||
|
|
||||||
|
|
||||||
typedef std::optional<std::string> OptString;
|
typedef std::optional<std::string> OptString;
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Min(T a, T b) { return a > b ? b : a; }
|
T Min(T a, T b) { return a > b ? b : a; }
|
||||||
template size_t Min<size_t>(size_t a, size_t b);
|
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);
|
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_
|
#endif // KEPP__DEFS_H_
|
||||||
|
|
85
File.cc
85
File.cc
|
@ -21,12 +21,13 @@
|
||||||
/// SOFTWARE.
|
/// SOFTWARE.
|
||||||
///
|
///
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include "File.h"
|
#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_
|
#define KEPP__FILE_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -32,6 +33,12 @@
|
||||||
#include "Defs.h"
|
#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 =
|
static constexpr std::ios::openmode DefaultMode =
|
||||||
std::ios::in|std::ios::out;
|
std::ios::in|std::ios::out;
|
||||||
|
|
||||||
|
@ -41,18 +48,41 @@ class File {
|
||||||
public:
|
public:
|
||||||
File(std::string fPath);
|
File(std::string fPath);
|
||||||
|
|
||||||
const std::string &Path() const;
|
const std::string Path();
|
||||||
void SetPath(const std::string &fPath);
|
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; };
|
[[nodiscard]] bool IsReadOnly() const { return this->readOnly; };
|
||||||
void MarkReadOnly() { this->readOnly = true; }
|
void MarkReadOnly() { this->readOnly = true; }
|
||||||
void ClearReadOnly() { this->readOnly = false; }
|
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:
|
private:
|
||||||
std::string path;
|
|
||||||
|
std::filesystem::path path;
|
||||||
bool readOnly;
|
bool readOnly;
|
||||||
std::ios::openmode mode;
|
std::ios::openmode mode;
|
||||||
};
|
};
|
||||||
|
|
10
main.cc
10
main.cc
|
@ -26,12 +26,14 @@
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
|
#include "LineEnding.h"
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(std::ostream &os, int exitCode)
|
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 << "\nUsage:\n";
|
||||||
os << "\tke [files]\n";
|
os << "\tke [files]\n";
|
||||||
exit(exitCode);
|
exit(exitCode);
|
||||||
|
@ -46,18 +48,16 @@ ShowDist(Cursor a, Cursor b)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if ((argc == 2) && (std::string(argv[1]) == "-h")) {
|
if ((argc == 2) && (std::string(argv[1]) == "-h")) {
|
||||||
|
std::cout << "help?\n";
|
||||||
usage(std::cout, 0);
|
usage(std::cout, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer frame;
|
Buffer frame;
|
||||||
std::cout << frame.Name() << "\n";
|
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;
|
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