Archived
1
Fork 0
This repository has been archived on 2024-10-07. You can view files and clone it, but cannot push or open issues or pull requests.
kilo/src/buffer.c
Hadeed Ahmad c4af9bda7c Make newline behavior consistent with vim
Assume every line ends with a newline, including the last line
2023-09-24 04:50:45 +05:00

203 lines
4.7 KiB
C

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "buffer.h"
#include "erow.h"
#include "utils.h"
static void buffer_free_rows(struct buffer *buffer);
static char *buffer_get_string(struct buffer *buffer, size_t *len_p);
struct buffer *buffer_create(void) {
struct buffer *buffer = malloc(sizeof(struct buffer));
buffer->filename = NULL;
buffer->cx = buffer->cy = buffer->rx = 0;
buffer->row_off = buffer->col_off = 0;
buffer->rows = NULL;
buffer->n_rows = 0;
buffer->modified = false;
return buffer;
}
ERRCODE buffer_read_file(struct buffer *buffer, const char *filename) {
ERRCODE errcode = 0;
if (buffer->filename) free(buffer->filename);
size_t filename_len = strlen(filename);
buffer->filename = malloc(filename_len);
memcpy(buffer->filename, filename, filename_len);
if (buffer->rows)
buffer_free_rows(buffer);
size_t buf_cap = 64;
char *buf = malloc(buf_cap);
FILE *file = fopen(filename, "r");
if (file == NULL)
RETURN(-1);
while (true) {
char c;
size_t buf_size = 0;
while ((c = getc(file)) != '\n' && c != EOF) {
if (buf_size >= buf_cap)
buf = realloc(buf, buf_cap *= 2);
buf[buf_size++] = c;
}
struct erow* erow = erow_create(buf, buf_size, buffer);
buffer_insert_row(buffer, erow, buffer->n_rows);
if (c == EOF)
break;
}
if (buffer->rows[buffer->n_rows - 1]->n_chars == 0)
buffer_delete_row(buffer, buffer->n_rows - 1);
END:
if (file != NULL)
fclose(file);
if (buf != NULL)
free(buf);
buffer->modified = false;
return errcode;
}
ERRCODE buffer_write_file(struct buffer *buffer, size_t *bytes_written) {
ERRCODE errcode = 0;
FILE *file = NULL;
char *write_buffer = NULL;
if (buffer->filename == NULL)
RETURN(-1);
size_t n_chars;
write_buffer = buffer_get_string(buffer, &n_chars);
file = fopen(buffer->filename, "w");
if (file == NULL)
RETURN(-2);
*bytes_written = fwrite(write_buffer, 1, n_chars, file);
if (*bytes_written != n_chars)
RETURN(-3);
END:
if (file != NULL)
fclose(file);
if (write_buffer)
free(write_buffer);
if (errcode == 0)
buffer->modified = false;
return errcode;
}
ERRCODE buffer_get_row_chars(struct buffer *buffer, char **chars, size_t *n_chars, int at) {
if (buffer == NULL)
return -1;
if (!(0 <= at && at <= buffer->n_rows))
return -2;
if (chars) *chars = buffer->rows[at]->chars;
if (n_chars) *n_chars = buffer->rows[at]->n_chars;
return 0;
}
ERRCODE buffer_get_row_rchars(struct buffer *buffer, char **rchars, size_t *n_rchars, int at) {
if (buffer == NULL)
return -1;
if (!(0 <= at && at <= buffer->n_rows))
return -2;
if (rchars) *rchars = buffer->rows[at]->rchars;
if (n_rchars) *n_rchars = buffer->rows[at]->n_rchars;
return 0;
}
void buffer_insert_row(struct buffer *buffer, struct erow *erow, int at) {
if (!(0 <= at && at <= buffer->n_rows))
return;
buffer->rows = realloc(buffer->rows, sizeof(struct erow *) * (buffer->n_rows + 1));
memmove(buffer->rows + at + 1, buffer->rows + at, sizeof(struct erow *) * (buffer->n_rows - at));
buffer->rows[at] = erow;
buffer->n_rows++;
}
void buffer_delete_row(struct buffer *buffer, int at) {
if (!(0 <= at && at < buffer->n_rows))
return;
erow_free(buffer->rows[at]);
memmove(buffer->rows + at, buffer->rows + at + 1, sizeof(struct erow *) * (buffer->n_rows - at - 1));
buffer->n_rows--;
buffer->modified = true;
}
struct erow *buffer_get_crow(struct buffer *buffer) {
return (buffer->cy < buffer->n_rows ? buffer->rows[buffer->cy]: NULL);
}
void buffer_free(struct buffer *buffer) {
free(buffer->filename);
buffer_free_rows(buffer);
}
size_t buffer_get_crow_len(struct buffer *buffer) {
struct erow *crow = buffer_get_crow(buffer);
return crow ? crow->n_chars : 0;
}
static void buffer_free_rows(struct buffer *buffer) {
for (int i = 0; i < buffer->n_rows; i++)
erow_free(buffer->rows[i]);
free(buffer->rows);
buffer->rows = NULL;
buffer->n_rows = 0;
}
static char *buffer_get_string(struct buffer *buffer, size_t *n_chars) {
*n_chars = 0;
for (int i = 0; i < buffer->n_rows; i++)
*n_chars += buffer->rows[i]->n_chars + 1;
char *write_buffer = malloc(*n_chars);
for (int i = 0, j = 0; i < buffer->n_rows; i++) {
struct erow *row = buffer->rows[i];
memcpy(write_buffer + j, row->chars, row->n_chars);
j += row->n_chars;
write_buffer[j++] = '\n';
}
return write_buffer;
}