Add more ed commands.
This commit is contained in:
@@ -14,7 +14,7 @@ done.
|
|||||||
|
|
||||||
Ed is an ed (the posix line editor) implementation using `Vase`.
|
Ed is an ed (the posix line editor) implementation using `Vase`.
|
||||||
<br/>
|
<br/>
|
||||||
Not done yet.
|
Mostly done.
|
||||||
|
|
||||||
#### `hl`
|
#### `hl`
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,13 @@ struct Command {
|
|||||||
Print,
|
Print,
|
||||||
Number,
|
Number,
|
||||||
Append,
|
Append,
|
||||||
|
Insert,
|
||||||
Change,
|
Change,
|
||||||
Delete,
|
Delete,
|
||||||
Write,
|
Write,
|
||||||
|
Edit,
|
||||||
|
ForceEdit,
|
||||||
|
Filename,
|
||||||
Dump,
|
Dump,
|
||||||
None
|
None
|
||||||
} type;
|
} type;
|
||||||
@@ -56,22 +60,24 @@ struct Ed {
|
|||||||
uint64_t line = 0;
|
uint64_t line = 0;
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
bool quitting = false;
|
bool quitting = false;
|
||||||
|
bool editing = false;
|
||||||
uint64_t marks[26]{0};
|
uint64_t marks[26]{0};
|
||||||
std::string last_regex = "";
|
std::string last_regex = "";
|
||||||
bool help_mode = false;
|
bool help_mode = false;
|
||||||
bool suppress_mode = false;
|
bool suppress_mode = false;
|
||||||
bool prompt_mode = false;
|
bool prompt_mode = false;
|
||||||
std::string prompt = "*";
|
std::string prompt = "*";
|
||||||
|
std::filesystem::path save_path = "";
|
||||||
std::string last_message = "";
|
std::string last_message = "";
|
||||||
|
|
||||||
Ed(std::filesystem::path file, bool suppress_mode, std::string prompt_)
|
Ed(std::string file_path, bool suppress_mode, std::string prompt_)
|
||||||
: vase(file, "/tmp"), suppress_mode(suppress_mode), prompt(prompt_) {
|
: vase("/tmp"), suppress_mode(suppress_mode), prompt(prompt_) {
|
||||||
if (prompt == "")
|
if (prompt == "")
|
||||||
prompt = "*";
|
prompt = "*";
|
||||||
else
|
else
|
||||||
prompt_mode = true;
|
prompt_mode = true;
|
||||||
line = vase.lines();
|
if (file_path != "")
|
||||||
std::cout << vase.length() << std::endl;
|
handle("E " + file_path, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr);
|
void parse_address(std::string_view cmd, uint64_t &i, Command::Address &addr);
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ struct Shard {
|
|||||||
static void retain(Shard *n);
|
static void retain(Shard *n);
|
||||||
static void release(Shard *n);
|
static void release(Shard *n);
|
||||||
|
|
||||||
static Shard *from_file(std::filesystem::path path, OriginalBuffer *b, bool posix_ending);
|
static Shard *from_file(std::filesystem::path &path, OriginalBuffer *b, bool posix_ending);
|
||||||
static std::vector<Shard *> from_swap(std::filesystem::path path, OriginalBuffer *b);
|
static Shard *from_command(const char *cmd, OriginalBuffer *o, bool posix_ending);
|
||||||
|
static std::vector<Shard *> from_swap(std::filesystem::path &path, OriginalBuffer *b);
|
||||||
|
|
||||||
static std::pair<Shard *, Shard *> split(Shard *n, uint64_t offset);
|
static std::pair<Shard *, Shard *> split(Shard *n, uint64_t offset);
|
||||||
static Shard *concat(Shard *left, Shard *right);
|
static Shard *concat(Shard *left, Shard *right);
|
||||||
|
|||||||
@@ -56,7 +56,13 @@ struct Vase {
|
|||||||
std::filesystem::path swapdir;
|
std::filesystem::path swapdir;
|
||||||
|
|
||||||
Vase(std::filesystem::path path, std::filesystem::path swapdir);
|
Vase(std::filesystem::path path, std::filesystem::path swapdir);
|
||||||
|
Vase(std::string cmd, std::filesystem::path swapdir);
|
||||||
|
Vase(std::filesystem::path swapdir);
|
||||||
~Vase();
|
~Vase();
|
||||||
|
Vase(Vase &&other) noexcept;
|
||||||
|
Vase &operator=(Vase &&other) noexcept;
|
||||||
|
Vase(const Vase &) = delete;
|
||||||
|
Vase &operator=(const Vase &) = delete;
|
||||||
|
|
||||||
uint64_t length();
|
uint64_t length();
|
||||||
uint64_t lines();
|
uint64_t lines();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ void help() {}
|
|||||||
|
|
||||||
void run(std::vector<std::string> args) {
|
void run(std::vector<std::string> args) {
|
||||||
std::string prompt = "";
|
std::string prompt = "";
|
||||||
std::filesystem::path filepath;
|
std::string file;
|
||||||
bool suppress = false;
|
bool suppress = false;
|
||||||
for (size_t i = 1; i < args.size(); i++) {
|
for (size_t i = 1; i < args.size(); i++) {
|
||||||
if (args[i] == "-p") {
|
if (args[i] == "-p") {
|
||||||
@@ -21,12 +21,12 @@ void run(std::vector<std::string> args) {
|
|||||||
} else if (args[i] == "-s") {
|
} else if (args[i] == "-s") {
|
||||||
suppress = true;
|
suppress = true;
|
||||||
} else {
|
} else {
|
||||||
if (filepath.string().size())
|
if (file.size())
|
||||||
throw crib::cli::cli_error("Invalid arguments given.", 1);
|
throw crib::cli::cli_error("Invalid arguments given.", 1);
|
||||||
filepath = args[i];
|
file = args[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ed ed(filepath, suppress, prompt);
|
Ed ed(file, suppress, prompt);
|
||||||
std::string command;
|
std::string command;
|
||||||
while (true) {
|
while (true) {
|
||||||
std::string cmd;
|
std::string cmd;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
Command command = parse(cmd, eof);
|
Command command = parse(cmd, eof);
|
||||||
bool was_quitting = quitting;
|
bool was_quitting = quitting;
|
||||||
quitting = false;
|
quitting = false;
|
||||||
|
bool was_editing = editing;
|
||||||
|
editing = false;
|
||||||
switch (command.type) {
|
switch (command.type) {
|
||||||
case Command::Type::Quit:
|
case Command::Type::Quit:
|
||||||
if (modified && !was_quitting) {
|
if (modified && !was_quitting) {
|
||||||
@@ -97,8 +99,6 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
text.append(cline);
|
text.append(cline);
|
||||||
text.push_back('\n');
|
text.push_back('\n');
|
||||||
}
|
}
|
||||||
if (std::cin.eof())
|
|
||||||
throw ed_error("EOF reached before '.' during text input.");
|
|
||||||
if (command.start.type != Command::Address::Type::None) {
|
if (command.start.type != Command::Address::Type::None) {
|
||||||
if (command.address_flags & Command::RANGE)
|
if (command.address_flags & Command::RANGE)
|
||||||
resolve_address(command.end, &line);
|
resolve_address(command.end, &line);
|
||||||
@@ -115,6 +115,32 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
modified = true;
|
modified = true;
|
||||||
line += line_count;
|
line += line_count;
|
||||||
} break;
|
} break;
|
||||||
|
case Command::Type::Insert: {
|
||||||
|
std::string text;
|
||||||
|
std::string cline;
|
||||||
|
uint64_t line_count = 0;
|
||||||
|
while (std::getline(std::cin, cline)) {
|
||||||
|
if (cline == ".")
|
||||||
|
break;
|
||||||
|
line_count++;
|
||||||
|
text.append(cline);
|
||||||
|
text.push_back('\n');
|
||||||
|
}
|
||||||
|
if (command.start.type != Command::Address::Type::None) {
|
||||||
|
if (command.address_flags & Command::RANGE)
|
||||||
|
resolve_address(command.end, &line);
|
||||||
|
else
|
||||||
|
resolve_address(command.start, &line);
|
||||||
|
}
|
||||||
|
if (line == 0)
|
||||||
|
line = 1;
|
||||||
|
if (text.empty())
|
||||||
|
break;
|
||||||
|
vase.snapshot();
|
||||||
|
append(text, line - 1);
|
||||||
|
modified = true;
|
||||||
|
line += line_count - 1;
|
||||||
|
} break;
|
||||||
case Command::Type::Change: {
|
case Command::Type::Change: {
|
||||||
uint64_t line_start = line;
|
uint64_t line_start = line;
|
||||||
uint64_t line_end = line;
|
uint64_t line_end = line;
|
||||||
@@ -138,8 +164,6 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
text.append(cline);
|
text.append(cline);
|
||||||
text.push_back('\n');
|
text.push_back('\n');
|
||||||
}
|
}
|
||||||
if (std::cin.eof())
|
|
||||||
throw ed_error("EOF reached before '.' during text input.");
|
|
||||||
vase.snapshot();
|
vase.snapshot();
|
||||||
remove(line_start, line_end);
|
remove(line_start, line_end);
|
||||||
line = line_start;
|
line = line_start;
|
||||||
@@ -172,9 +196,9 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
case Command::Type::Write: {
|
case Command::Type::Write: {
|
||||||
std::string path = command.argument;
|
std::string path = command.argument;
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
path = vase.path;
|
path = save_path;
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
throw ed_error("Need filename to write to.");
|
throw ed_error("Need file to write to.");
|
||||||
}
|
}
|
||||||
uint64_t line_start = 1;
|
uint64_t line_start = 1;
|
||||||
uint64_t line_end = vase.lines();
|
uint64_t line_end = vase.lines();
|
||||||
@@ -207,7 +231,6 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
if (pclose(pipe) == -1)
|
if (pclose(pipe) == -1)
|
||||||
throw ed_error("Error closing command.");
|
throw ed_error("Error closing command.");
|
||||||
} else {
|
} else {
|
||||||
vase.path = path;
|
|
||||||
std::ofstream file(path, std::ios::out | std::ios::trunc);
|
std::ofstream file(path, std::ios::out | std::ios::trunc);
|
||||||
if (!file)
|
if (!file)
|
||||||
throw ed_error("Error writing to file.");
|
throw ed_error("Error writing to file.");
|
||||||
@@ -218,11 +241,68 @@ bool Ed::handle(std::string cmd, bool eof) {
|
|||||||
}
|
}
|
||||||
if (!file)
|
if (!file)
|
||||||
throw ed_error("Error writing to file.");
|
throw ed_error("Error writing to file.");
|
||||||
|
save_path = path;
|
||||||
modified = false;
|
modified = false;
|
||||||
}
|
}
|
||||||
if (!suppress_mode)
|
if (!suppress_mode)
|
||||||
std::cout << bytes << std::endl;
|
std::cout << bytes << std::endl;
|
||||||
} break;
|
} break;
|
||||||
|
case Command::Type::Edit: {
|
||||||
|
if (modified && !was_editing) {
|
||||||
|
editing = true;
|
||||||
|
throw ed_error("Buffer modified.");
|
||||||
|
}
|
||||||
|
std::string path = command.argument;
|
||||||
|
if (path.empty()) {
|
||||||
|
path = save_path;
|
||||||
|
if (path.empty())
|
||||||
|
throw ed_error("Need file to read from.");
|
||||||
|
}
|
||||||
|
if (path[0] == '!') {
|
||||||
|
path.erase(1);
|
||||||
|
Vase new_vase(std::string(path), "/tmp");
|
||||||
|
vase = std::move(new_vase);
|
||||||
|
modified = true;
|
||||||
|
} else {
|
||||||
|
Vase new_vase(std::filesystem::path(path), "/tmp");
|
||||||
|
vase = std::move(new_vase);
|
||||||
|
save_path = path;
|
||||||
|
modified = false;
|
||||||
|
}
|
||||||
|
line = vase.lines();
|
||||||
|
if (!suppress_mode)
|
||||||
|
std::cout << vase.length() << std::endl;
|
||||||
|
} break;
|
||||||
|
case Command::Type::ForceEdit: {
|
||||||
|
std::string path = command.argument;
|
||||||
|
if (path.empty()) {
|
||||||
|
path = save_path;
|
||||||
|
if (path.empty())
|
||||||
|
throw ed_error("Need file to read from.");
|
||||||
|
}
|
||||||
|
if (path[0] == '!') {
|
||||||
|
path.erase(0, 1);
|
||||||
|
Vase new_vase(std::string(path), "/tmp");
|
||||||
|
vase = std::move(new_vase);
|
||||||
|
modified = true;
|
||||||
|
} else {
|
||||||
|
Vase new_vase(std::filesystem::path(path), "/tmp");
|
||||||
|
vase = std::move(new_vase);
|
||||||
|
save_path = path;
|
||||||
|
modified = false;
|
||||||
|
}
|
||||||
|
line = vase.lines();
|
||||||
|
std::fill(std::begin(marks), std::end(marks), '\0');
|
||||||
|
if (!suppress_mode)
|
||||||
|
std::cout << vase.length() << std::endl;
|
||||||
|
} break;
|
||||||
|
case Command::Type::Filename: {
|
||||||
|
std::string path = command.argument;
|
||||||
|
if (path.empty())
|
||||||
|
throw ed_error("No filename given.");
|
||||||
|
save_path = path;
|
||||||
|
std::cout << save_path.string() << std::endl;
|
||||||
|
} break;
|
||||||
case Command::Type::Dump:
|
case Command::Type::Dump:
|
||||||
Shard::dump(vase.root);
|
Shard::dump(vase.root);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ Command Ed::parse(std::string cmd, bool eof) {
|
|||||||
command.type = Command::Type::Append;
|
command.type = Command::Type::Append;
|
||||||
i++;
|
i++;
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
command.type = Command::Type::Insert;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
command.type = Command::Type::Change;
|
command.type = Command::Type::Change;
|
||||||
i++;
|
i++;
|
||||||
@@ -98,6 +102,39 @@ Command Ed::parse(std::string cmd, bool eof) {
|
|||||||
throw ed_error("Invalid command.");
|
throw ed_error("Invalid command.");
|
||||||
command.argument = cmd.substr(i);
|
command.argument = cmd.substr(i);
|
||||||
return command;
|
return command;
|
||||||
|
case 'e':
|
||||||
|
command.type = Command::Type::Edit;
|
||||||
|
i++;
|
||||||
|
if (i >= cmd.size())
|
||||||
|
return command;
|
||||||
|
if (cmd[i] == ' ' || cmd[i] == '\t')
|
||||||
|
skip_space();
|
||||||
|
else
|
||||||
|
throw ed_error("Invalid command.");
|
||||||
|
command.argument = cmd.substr(i);
|
||||||
|
return command;
|
||||||
|
case 'E':
|
||||||
|
command.type = Command::Type::ForceEdit;
|
||||||
|
i++;
|
||||||
|
if (i >= cmd.size())
|
||||||
|
return command;
|
||||||
|
if (cmd[i] == ' ' || cmd[i] == '\t')
|
||||||
|
skip_space();
|
||||||
|
else
|
||||||
|
throw ed_error("Invalid command.");
|
||||||
|
command.argument = cmd.substr(i);
|
||||||
|
return command;
|
||||||
|
case 'f':
|
||||||
|
command.type = Command::Type::Filename;
|
||||||
|
i++;
|
||||||
|
if (i >= cmd.size())
|
||||||
|
return command;
|
||||||
|
if (cmd[i] == ' ' || cmd[i] == '\t')
|
||||||
|
skip_space();
|
||||||
|
else
|
||||||
|
throw ed_error("Invalid command.");
|
||||||
|
command.argument = cmd.substr(i);
|
||||||
|
return command;
|
||||||
case '#':
|
case '#':
|
||||||
command.type = Command::Type::Dump;
|
command.type = Command::Type::Dump;
|
||||||
i++;
|
i++;
|
||||||
|
|||||||
+117
-8
@@ -205,7 +205,112 @@ Shard *Shard::build(Shard **pieces, uint64_t lo, uint64_t hi) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shard *Shard::from_file(std::filesystem::path path, OriginalBuffer *o, bool posix_ending) {
|
static bool write_all(int fd, const void *data, size_t len) {
|
||||||
|
const char *p = static_cast<const char *>(data);
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t n = write(fd, p, len);
|
||||||
|
if (n > 0) {
|
||||||
|
p += n;
|
||||||
|
len -= (size_t)n;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (n == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shard *Shard::from_command(const char *cmd, OriginalBuffer *o, bool posix_ending) {
|
||||||
|
int dest_fd = o->fd;
|
||||||
|
if (dest_fd == -1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
FILE *pipe = popen(cmd, "r");
|
||||||
|
if (!pipe)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::vector<Shard *> pieces;
|
||||||
|
pieces.reserve(16);
|
||||||
|
|
||||||
|
uint64_t pos = 0;
|
||||||
|
char buf[PETAL_SIZE_MAX];
|
||||||
|
uint64_t buf_cursor = 0;
|
||||||
|
|
||||||
|
char ending[2] = {'\0', '\0'};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t got = fread(buf + buf_cursor, 1, sizeof(buf) - buf_cursor, pipe);
|
||||||
|
buf_cursor += got;
|
||||||
|
|
||||||
|
if (buf_cursor == PETAL_SIZE_MAX || feof(pipe)) {
|
||||||
|
if (buf_cursor == 0)
|
||||||
|
break;
|
||||||
|
uint64_t lines = 0;
|
||||||
|
const char *p = buf;
|
||||||
|
const char *end = p + buf_cursor;
|
||||||
|
while (p < end) {
|
||||||
|
const void *nl = memchr(p, '\n', end - p);
|
||||||
|
if (!nl)
|
||||||
|
break;
|
||||||
|
lines++;
|
||||||
|
p = (const char *)nl + 1;
|
||||||
|
}
|
||||||
|
if (buf_cursor >= 2) {
|
||||||
|
ending[0] = buf[buf_cursor - 2];
|
||||||
|
ending[1] = buf[buf_cursor - 1];
|
||||||
|
} else if (buf_cursor == 1) {
|
||||||
|
ending[0] = ending[1];
|
||||||
|
ending[1] = buf[0];
|
||||||
|
}
|
||||||
|
if (!write_all(dest_fd, buf, buf_cursor)) {
|
||||||
|
pclose(pipe);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
pieces.push_back(new Petal(buf_cursor, lines, o, pos));
|
||||||
|
pos += buf_cursor;
|
||||||
|
}
|
||||||
|
if (feof(pipe))
|
||||||
|
break;
|
||||||
|
if (ferror(pipe))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = pclose(pipe);
|
||||||
|
if (status == -1)
|
||||||
|
return nullptr;
|
||||||
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (pieces.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (posix_ending) {
|
||||||
|
if (ending[1] == '\n') {
|
||||||
|
Petal *last = (Petal *)pieces.back();
|
||||||
|
last->lines--;
|
||||||
|
last->length--;
|
||||||
|
if (last->length == 0) {
|
||||||
|
Shard::release(last);
|
||||||
|
pieces.pop_back();
|
||||||
|
last = nullptr;
|
||||||
|
if (!pieces.empty())
|
||||||
|
last = (Petal *)pieces.back();
|
||||||
|
}
|
||||||
|
if (last && ending[0] == '\r')
|
||||||
|
last->length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o->initialize();
|
||||||
|
|
||||||
|
if (pieces.size() == 1)
|
||||||
|
return pieces[0];
|
||||||
|
|
||||||
|
return build(pieces.data(), 0, pieces.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Shard *Shard::from_file(std::filesystem::path &path, OriginalBuffer *o, bool posix_ending) {
|
||||||
int dest_fd = o->fd;
|
int dest_fd = o->fd;
|
||||||
if (dest_fd == -1)
|
if (dest_fd == -1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -216,17 +321,22 @@ Shard *Shard::from_file(std::filesystem::path path, OriginalBuffer *o, bool posi
|
|||||||
uint64_t total = std::filesystem::file_size(path);
|
uint64_t total = std::filesystem::file_size(path);
|
||||||
if (posix_ending && total > 0) {
|
if (posix_ending && total > 0) {
|
||||||
char last;
|
char last;
|
||||||
char s_last;
|
|
||||||
if (pread(src_fd, &last, 1, (off_t)(total - 1)) != 1)
|
if (pread(src_fd, &last, 1, (off_t)(total - 1)) != 1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (pread(src_fd, &s_last, 1, (off_t)(total - 2)) != 1)
|
|
||||||
return nullptr;
|
|
||||||
if (last == '\n') {
|
if (last == '\n') {
|
||||||
total--;
|
total--;
|
||||||
if (s_last == '\r')
|
if (total > 0) {
|
||||||
total--;
|
char s_last;
|
||||||
|
if (pread(src_fd, &s_last, 1, (off_t)(total - 1)) != 1)
|
||||||
|
return nullptr;
|
||||||
|
if (s_last == '\r')
|
||||||
|
total--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (total == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
std::vector<Shard *> pieces;
|
std::vector<Shard *> pieces;
|
||||||
uint64_t pos = 0;
|
uint64_t pos = 0;
|
||||||
pieces.reserve((total + PETAL_SIZE_MAX - 1) / PETAL_SIZE_MAX);
|
pieces.reserve((total + PETAL_SIZE_MAX - 1) / PETAL_SIZE_MAX);
|
||||||
@@ -250,8 +360,7 @@ Shard *Shard::from_file(std::filesystem::path path, OriginalBuffer *o, bool posi
|
|||||||
lines++;
|
lines++;
|
||||||
p = (const char *)nl + 1;
|
p = (const char *)nl + 1;
|
||||||
}
|
}
|
||||||
ssize_t written = write(dest_fd, buf, take);
|
if (!write_all(dest_fd, buf, take)) {
|
||||||
if (written != (ssize_t)take) {
|
|
||||||
close(src_fd);
|
close(src_fd);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,78 @@ Vase::Vase(std::filesystem::path path, std::filesystem::path swapdir)
|
|||||||
Shard::retain(root);
|
Shard::retain(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vase::Vase(std::string cmd, std::filesystem::path swapdir)
|
||||||
|
: path(""), swapdir(swapdir) {
|
||||||
|
if (!std::filesystem::exists(swapdir) || !std::filesystem::is_directory(swapdir))
|
||||||
|
throw std::runtime_error("Swap directory does not exist or is not a directory.");
|
||||||
|
append = new AppendBuffer(swapdir);
|
||||||
|
original = new OriginalBuffer(swapdir);
|
||||||
|
root = Shard::from_command(cmd.c_str(), original, posix_ending);
|
||||||
|
history_top = 0;
|
||||||
|
history.push_back(root);
|
||||||
|
Shard::retain(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vase::Vase(std::filesystem::path swapdir)
|
||||||
|
: path(""), swapdir(swapdir) {
|
||||||
|
if (!std::filesystem::exists(swapdir) || !std::filesystem::is_directory(swapdir))
|
||||||
|
throw std::runtime_error("Swap directory does not exist or is not a directory.");
|
||||||
|
append = new AppendBuffer(swapdir);
|
||||||
|
original = new OriginalBuffer(swapdir);
|
||||||
|
root = nullptr;
|
||||||
|
history_top = 0;
|
||||||
|
history.push_back(root);
|
||||||
|
Shard::retain(root);
|
||||||
|
}
|
||||||
|
|
||||||
Vase::~Vase() {
|
Vase::~Vase() {
|
||||||
Shard::release(root);
|
Shard::release(root);
|
||||||
|
for (auto s : history)
|
||||||
|
Shard::release(s);
|
||||||
|
if (original)
|
||||||
|
delete original;
|
||||||
|
if (append)
|
||||||
|
delete append;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vase::Vase(Vase &&other) noexcept
|
||||||
|
: original(other.original),
|
||||||
|
append(other.append),
|
||||||
|
root(other.root),
|
||||||
|
posix_ending(other.posix_ending),
|
||||||
|
using_crlf(other.using_crlf),
|
||||||
|
path(std::move(other.path)),
|
||||||
|
swapdir(std::move(other.swapdir)),
|
||||||
|
history(std::move(other.history)),
|
||||||
|
history_top(other.history_top) {
|
||||||
|
other.original = nullptr;
|
||||||
|
other.append = nullptr;
|
||||||
|
other.root = nullptr;
|
||||||
|
other.history_top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vase &Vase::operator=(Vase &&other) noexcept {
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
Shard::release(root);
|
||||||
for (auto s : history)
|
for (auto s : history)
|
||||||
Shard::release(s);
|
Shard::release(s);
|
||||||
delete original;
|
delete original;
|
||||||
delete append;
|
delete append;
|
||||||
|
original = other.original;
|
||||||
|
append = other.append;
|
||||||
|
root = other.root;
|
||||||
|
posix_ending = other.posix_ending;
|
||||||
|
using_crlf = other.using_crlf;
|
||||||
|
path = std::move(other.path);
|
||||||
|
swapdir = std::move(other.swapdir);
|
||||||
|
history = std::move(other.history);
|
||||||
|
history_top = other.history_top;
|
||||||
|
other.original = nullptr;
|
||||||
|
other.append = nullptr;
|
||||||
|
other.root = nullptr;
|
||||||
|
other.history_top = 0;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Vase::length() {
|
uint64_t Vase::length() {
|
||||||
@@ -108,16 +174,21 @@ void Vase::snapshot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Vase::prune_history(uint64_t n) {
|
void Vase::prune_history(uint64_t n) {
|
||||||
n = std::min(n, history_top);
|
uint64_t keep = std::min(history.size(), n + 1);
|
||||||
for (uint64_t i = 0; i < n; ++i)
|
if (keep == history.size())
|
||||||
|
return;
|
||||||
|
uint64_t remove = history.size() - keep;
|
||||||
|
for (uint64_t i = 0; i < remove; ++i)
|
||||||
Shard::release(history[i]);
|
Shard::release(history[i]);
|
||||||
history.erase(history.begin(), history.begin() + n);
|
history.erase(history.begin(), history.begin() + remove);
|
||||||
history_top -= n;
|
history_top -= remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Vase::save() {
|
bool Vase::save() {
|
||||||
if (!root)
|
if (!root)
|
||||||
return true;
|
return true;
|
||||||
|
if (path == "")
|
||||||
|
return false;
|
||||||
std::ofstream file(path, std::ios::binary);
|
std::ofstream file(path, std::ios::binary);
|
||||||
if (!file)
|
if (!file)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user