commit 86dd70c41a66c874b49092caa1986ecedd36f254
parent 36a12616e748e39265af475dbaee5e8356cc984a
Author: lumidify <nobody@lumidify.org>
Date: Wed, 22 Sep 2021 20:17:12 +0200
Add basic file loading and writing functionality
Diffstat:
M | buffer.c | | | 103 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
M | buffer.h | | | 8 | ++++++-- |
M | commands.c | | | 9 | +++++++-- |
M | ledit.c | | | 13 | ++++++++++++- |
4 files changed, 122 insertions(+), 11 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -1,8 +1,10 @@
/* FIXME: shrink buffers when text length less than a fourth of the size */
/* FIXME: also cache PangoLayouts since keeping them around isn't really of much use? */
+#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <limits.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -44,6 +46,7 @@ ledit_create_buffer(ledit_common_state *state) {
ledit_buffer *buffer = ledit_malloc(sizeof(ledit_buffer));
buffer->state = state;
buffer->lines = NULL;
+ buffer->filename = NULL;
buffer->lines_num = 0;
buffer->lines_cap = 0;
buffer->cur_line = 0;
@@ -62,6 +65,84 @@ ledit_create_buffer(ledit_common_state *state) {
return buffer;
}
+/* FIXME: don't generate extra blank line at end! */
+/* WARNING: errstr must be copied as soon as possible! */
+int
+ledit_load_file_into_buffer(ledit_buffer *buffer, char *filename, int line, char **errstr) {
+ long len;
+ int off = 0;
+ ledit_line *ll;
+ char *file_contents;
+ FILE *file;
+
+ file = fopen(filename, "r");
+ if (!file) goto error;
+ if (fseek(file, 0, SEEK_END)) goto errorclose;
+ len = ftell(file);
+ if (len < 0) goto errorclose;
+ if (fseek(file, 0, SEEK_SET)) goto errorclose;
+
+ ll = ledit_get_line(buffer, line);
+ file_contents = ledit_malloc(len + 2);
+ /* mimic nvi (or at least the openbsd version) - if the line
+ is empty, insert directly, otherwise insert after the line */
+ if (ll->len > 0) {
+ off = 1;
+ file_contents[0] = '\n';
+ }
+ clearerr(file);
+ fread(file_contents + off, 1, (size_t)len, file);
+ if (ferror(file)) goto errorclose;
+ file_contents[len + off] = '\0';
+ /* don't generate extra newline at end */
+ if (len + off > 1 && file_contents[len + off - 1 == '\n']) {
+ file_contents[len + off - 1] = '\0';
+ len--;
+ }
+ if (fclose(file)) goto error;
+
+ ledit_insert_text_with_newlines(
+ buffer, line, ll->len, file_contents, len + off, NULL, NULL
+ );
+ free(file_contents);
+ return 0;
+error:
+ if (*errstr)
+ *errstr = strerror(errno);
+ return 1;
+errorclose:
+ if (*errstr)
+ *errstr = strerror(errno);
+ fclose(file);
+ return 1;
+}
+
+/* FIXME: allow to write only certain lines */
+int
+ledit_write_buffer_to_file(ledit_buffer *buffer, char *filename, char **errstr) {
+ FILE *file;
+ ledit_line *ll;
+ file = fopen(filename, "w");
+ if (!file) goto error;
+ clearerr(file);
+ for (int i = 0; i < buffer->lines_num; i++) {
+ ll = ledit_get_line(buffer, i);
+ ledit_normalize_line(ll);
+ if (fprintf(file, "%s\n", ll->text) < 0) goto errorclose;
+ }
+ if (fclose(file)) goto error;
+ return 0;
+error:
+ if (*errstr)
+ *errstr = strerror(errno);
+ return 1;
+errorclose:
+ if (*errstr)
+ *errstr = strerror(errno);
+ fclose(file);
+ return 1;
+}
+
void
ledit_destroy_buffer(ledit_buffer *buffer) {
ledit_line *l;
@@ -71,6 +152,7 @@ ledit_destroy_buffer(ledit_buffer *buffer) {
free(l->text);
}
free(buffer->lines);
+ if (buffer->filename) free(buffer->filename);
free(buffer);
}
@@ -84,6 +166,7 @@ ledit_normalize_line(ledit_line *line) {
);
line->gap = line->len;
}
+ /* FIXME: check if enough space, just to be sure */
line->text[line->len] = '\0';
}
@@ -338,8 +421,8 @@ ledit_insert_text_final(ledit_buffer *buffer, int line_index, int index, char *t
/* FIXME: this isn't optimized like the standard version, but whatever */
static char *
-strchr_len(char *text, char c, int len) {
- for (int i = 0; i < len; i++) {
+strchr_len(char *text, char c, long len) {
+ for (long i = 0; i < len; i++) {
if (text[i] == c)
return text + i;
}
@@ -347,11 +430,18 @@ strchr_len(char *text, char c, int len) {
}
/* FIXME: make these functions that call recalc* also be final as described above */
+/* FIXME: Sort out integer types.
+ -> len is long here mainly because that's what ftell(3) returns and it sort of
+ makes sense since a file can be very long (although ledit probably won't work
+ with such long files anyways). The individual lines have to use int anyways
+ because of pango.
+ Maybe len isn't needed anyways? It might be possible to enforce that text
+ just always has to be null-terminated. */
void
ledit_insert_text_with_newlines(
ledit_buffer *buffer,
int line_index, int index,
- char *text, int len,
+ char *text, long len,
int *end_line_ret, int *end_char_ret) {
int end;
ledit_insert_text_with_newlines_base(
@@ -366,15 +456,16 @@ ledit_insert_text_with_newlines(
ledit_recalc_from_line(buffer, line_index);
}
+/* FIXME: Check for integer overflow when casting to int */
void
ledit_insert_text_with_newlines_base(
ledit_buffer *buffer,
int line_index, int index,
- char *text, int len,
+ char *text, long len,
int *end_line_ret, int *end_char_ret) {
if (len == -1)
len = strlen(text);
- int rem_len = len;
+ long rem_len = len;
char *cur, *last = text;
int cur_line = line_index;
int cur_index = index;
@@ -384,8 +475,8 @@ ledit_insert_text_with_newlines_base(
ledit_insert_text_base(buffer, cur_line, cur_index, last, cur - last);
cur_index = 0;
cur_line++;
- last = cur + 1;
rem_len -= cur - last + 1;
+ last = cur + 1;
}
/* FIXME: check how legal this casting between pointers and ints is */
ledit_insert_text_base(buffer, cur_line, cur_index, last, text + len - last);
diff --git a/buffer.h b/buffer.h
@@ -25,9 +25,11 @@ typedef struct {
char h_dirty; /* whether height needs to be recalculated still */
} ledit_line;
+/* TODO: advisory lock on file? also check if modification date changed before writing */
struct ledit_buffer {
ledit_common_state *state; /* general state, e.g. display, window, etc. */
ledit_line *lines; /* array of lines */
+ char *filename;
int lines_cap; /* number of lines allocated in array */
int lines_num; /* number of used lines */
int cur_line; /* current line */
@@ -44,6 +46,8 @@ struct ledit_buffer {
};
ledit_buffer *ledit_create_buffer(ledit_common_state *state);
+int ledit_load_file_into_buffer(ledit_buffer *buffer, char *filename, int line, char **errstr);
+int ledit_write_buffer_to_file(ledit_buffer *buffer, char *filename, char **errstr);
void ledit_destroy_buffer(ledit_buffer *buffer);
void ledit_normalize_line(ledit_line *line);
void ledit_set_line_selection(ledit_buffer *buffer, int line, int start_byte, int end_byte);
@@ -80,7 +84,7 @@ void ledit_insert_text_base(ledit_buffer *buffer, int line_index, int index, cha
void ledit_insert_text_with_newlines_base(
ledit_buffer *buffer,
int line_index, int index,
- char *text, int len,
+ char *text, long len,
int *end_line_ret, int *end_char_ret
);
void ledit_append_line_base(ledit_buffer *buffer, int line_index, int text_index);
@@ -105,7 +109,7 @@ void ledit_insert_text(ledit_buffer *buffer, int line_index, int index, char *te
void ledit_insert_text_with_newlines(
ledit_buffer *buffer,
int line_index, int index,
- char *text, int len,
+ char *text, long len,
int *end_line_ret, int *end_char_ret
);
void ledit_append_line(ledit_buffer *buffer, int line_index, int text_index);
diff --git a/commands.c b/commands.c
@@ -1,5 +1,6 @@
/* FIXME: Parse commands properly and allow combinations of commands */
#include <ctype.h>
+#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <pango/pangoxft.h>
@@ -16,7 +17,10 @@ handle_write(ledit_buffer *buffer, char *cmd, int l1, int l2) {
(void)cmd;
(void)l1;
(void)l2;
- printf("write\n");
+ /* FIXME: Implement properly; handle error */
+ char *errstr;
+ if (buffer->filename)
+ ledit_write_buffer_to_file(buffer, buffer->filename, &errstr);
return 0;
}
@@ -26,7 +30,8 @@ handle_quit(ledit_buffer *buffer, char *cmd, int l1, int l2) {
(void)cmd;
(void)l1;
(void)l2;
- printf("quit\n");
+ /* FIXME: Implement */
+ exit(1);
return 0;
}
diff --git a/ledit.c b/ledit.c
@@ -37,6 +37,7 @@
#include "cache.h"
#include "util.h"
#include "undo.h"
+#include "commands.h"
enum key_type {
KEY_NONE = 0,
@@ -1021,7 +1022,17 @@ setup(int argc, char *argv[]) {
buffer = ledit_create_buffer(&state);
/* FIXME: move this to create_buffer */
ledit_init_undo_stack(buffer);
- set_mode(INSERT);
+ /* FIXME: Support multiple buffers/files */
+ if (argc > 1) {
+ char *load_err;
+ if (ledit_load_file_into_buffer(buffer, argv[1], 0, &load_err)) {
+ fprintf(stderr, "Error opening file '%s': %s\n", argv[1], load_err);
+ exit(1);
+ }
+ buffer->filename = ledit_strdup(argv[1]);
+ }
+ set_mode(NORMAL);
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
key_stack.len = key_stack.alloc = 0;
key_stack.stack = NULL;