summaryrefslogtreecommitdiff
path: root/file.c
blob: 59e8179b58ce2583c7548301e5db672514aab5f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "file.h"

#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "error.h"
#include "line.h"
#include "syntax.h"
#include "window.h"

static char *lines_to_string(struct editor_state *editor, int *buffer_length)
{
	int total_length = 0;
	int j;

	for (j = 0; j < editor->num_lines; j++)
		total_length += editor->lines[j].size + 1;

	*buffer_length = total_length;

	char* buffer = malloc(total_length);
	char* p = buffer;

	for (j = 0; j < editor->num_lines; j++) {
		memcpy(p, editor->lines[j].chars, editor->lines[j].size);
		p += editor->lines[j].size;
		*p = '\n';
		p++;
	}

	return buffer;
}

void editor_open(struct editor_state* editor, char* filename)
{
	free(editor->filename);
	size_t filename_len = strlen(filename) + 1;
	editor->filename = malloc(filename_len);
	memcpy(editor->filename, filename, filename_len);

	editor_select_syntax_highlight(editor);
	window_set_filename(filename);

	/* If there is no file with this name, the editor will create it on save. */
	if (access(filename, F_OK) != 0)
		return;

	FILE* fp = fopen(filename, "r");
	if (!fp) {
		fatal_error("Failed to read file from %s\n", filename);
	}

	char* line = NULL;
	size_t line_capacity = 0;
	ssize_t line_length;

	while ((line_length = getline(&line, &line_capacity, fp)) != -1) {
		while (line_length > 0 && (line[line_length - 1] == '\n' || line[line_length - 1] == '\r'))
			line_length--;

		editor_insert_line(editor, editor->num_lines, line, line_length);
	}

	free(line);
	fclose(fp);

	editor->dirty = 0;
}

int file_save_current_file(struct editor_state *editor)
{
	/* Assume that the editor has already prompted the user for a name */
	if (editor->filename == NULL)
		return EINVAL;

	int length;
	char *buffer = lines_to_string(editor, &length);

	int fd = open(editor->filename, O_RDWR | O_CREAT, 0644);
	if (fd == -1)
		goto fail;

	if (ftruncate(fd, length) == -1)
		goto fail;

	if (write(fd, buffer, length) != length)
		goto fail;

	close(fd);
	free(buffer);
	editor_set_status_message(editor, "%d bytes written to disk", length);
	editor->dirty = 0;

	return 0;

fail:
	int saved_errno = errno;
	close(fd);
	free(buffer);
	return saved_errno;
}