URI: 
       tAdd basic file loading and writing functionality - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 86dd70c41a66c874b49092caa1986ecedd36f254
   DIR parent 36a12616e748e39265af475dbaee5e8356cc984a
  HTML 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(-)
       ---
   DIR diff --git a/buffer.c b/buffer.c
       t@@ -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>
       t@@ -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;
       t@@ -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;
       t@@ -71,6 +152,7 @@ ledit_destroy_buffer(ledit_buffer *buffer) {
                        free(l->text);
                }
                free(buffer->lines);
       +        if (buffer->filename) free(buffer->filename);
                free(buffer);
        }
        
       t@@ -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';
        }
        
       t@@ -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;
                }
       t@@ -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(
       t@@ -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;
       t@@ -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);
   DIR diff --git a/buffer.h b/buffer.h
       t@@ -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 */
       t@@ -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);
       t@@ -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);
       t@@ -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);
   DIR diff --git a/commands.c b/commands.c
       t@@ -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>
       t@@ -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;
        }
        
       t@@ -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;
        }
        
   DIR diff --git a/ledit.c b/ledit.c
       t@@ -37,6 +37,7 @@
        #include "cache.h"
        #include "util.h"
        #include "undo.h"
       +#include "commands.h"
        
        enum key_type {
                KEY_NONE = 0,
       t@@ -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;