Files
ke/file_io.cc
2025-11-25 09:17:50 -08:00

181 lines
3.8 KiB
C++

#include "file_io.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <ctime>
// Need access to main.cc structures and functions
extern void erow_insert(int at, const char *s, int len);
extern void reset_editor();
extern void editor_set_status(const char *fmt, ...);
extern void die(const char *s);
extern char *editor_prompt(const char *, void (*cb)(char *, int16_t));
// erow definition
struct erow {
char *line;
char *render;
int size;
int rsize;
int cap;
};
// editor_t definition
struct editor_t {
struct termios entry_term;
int rows, cols;
int curx, cury;
int rx;
int mode;
int nrows;
int rowoffs, coloffs;
struct erow *row;
struct erow *killring;
int kill;
int no_kill;
char *filename;
int dirty;
int dirtyex;
char msg[80];
int mark_set;
int mark_curx, mark_cury;
time_t msgtm;
};
namespace ke {
void FileIO::open_file(editor_t* editor, const char* filename) {
char* line = nullptr;
size_t linecap = 0;
ssize_t linelen;
FILE* fp = nullptr;
reset_editor();
editor->filename = strdup(filename);
assert(editor->filename != nullptr);
editor->dirty = 0;
if ((fp = fopen(filename, "r")) == nullptr) {
if (errno == ENOENT) {
editor_set_status("[new file]");
return;
}
die("fopen");
}
while ((linelen = getline(&line, &linecap, fp)) != -1) {
if (linelen != -1) {
while ((linelen > 0) && ((line[linelen - 1] == '\r') ||
(line[linelen - 1] == '\n'))) {
linelen--;
}
erow_insert(editor->nrows, line, linelen);
}
}
free(line);
line = nullptr;
fclose(fp);
}
char* FileIO::rows_to_buffer(editor_t* editor, int* buflen) {
int len = 0;
int j;
char* buf = nullptr;
char* p = nullptr;
for (j = 0; j < editor->nrows; j++) {
/* extra byte for newline */
len += editor->row[j].size + 1;
}
if (len == 0) {
return nullptr;
}
*buflen = len;
buf = static_cast<char*>(malloc(len));
assert(buf != nullptr);
p = buf;
for (j = 0; j < editor->nrows; j++) {
memcpy(p, editor->row[j].line, editor->row[j].size);
p += editor->row[j].size;
*p++ = '\n';
}
return buf;
}
int FileIO::save_file(editor_t* editor) {
int fd = -1;
int len;
int status = 1; /* will be used as exit code */
char* buf;
if (!editor->dirty) {
editor_set_status("No changes to save.");
return 0;
}
if (editor->filename == nullptr) {
editor->filename = editor_prompt("Filename: %s", nullptr);
if (editor->filename == nullptr) {
editor_set_status("Save aborted.");
return 0;
}
}
buf = rows_to_buffer(editor, &len);
if ((fd = open(editor->filename, O_RDWR | O_CREAT, 0644)) == -1) {
goto save_exit;
}
if (-1 == ftruncate(fd, len)) {
goto save_exit;
}
if (len == 0) {
status = 0;
goto save_exit;
}
if ((ssize_t) len != write(fd, buf, len)) {
goto save_exit;
}
status = 0;
save_exit:
if (fd)
close(fd);
if (buf) {
free(buf);
buf = nullptr;
}
if (status != 0) {
buf = strerror(errno);
editor_set_status("Error writing %s: %s",
editor->filename,
buf);
} else {
editor_set_status("Wrote %d bytes to %s.",
len,
editor->filename);
editor->dirty = 0;
}
return status;
}
} // namespace ke