#define _GNU_SOURCE
#include <string.h>
#include <assert.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include "edit.h"
+typedef struct {
+ char* buf;
+ size_t len;
+} FMap;
+
+FMap fmap(char* path) {
+ int fd;
+ FMap file;
+ struct stat sb;
+ if ((fd = open(path, O_RDONLY, 0)) < 0)
+ die("could not open file");
+ if (fstat(fd, &sb) < 0)
+ die("file size could not be determined");
+ file.buf = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ file.len = sb.st_size;
+ if (file.buf == MAP_FAILED)
+ die("memory mapping of file failed");
+ return file;
+}
+
+void funmap(FMap file) {
+ munmap(file.buf, file.len);
+}
+
void buf_load(Buf* buf, char* path) {
buf->insert_mode = true;
- unsigned i = 0;
- Rune r;
- FILE* in = (!strcmp(path,"-") ? stdin : fopen(path, "rb"));
- buf->path = (in == stdin ? NULL : strdup(path));
- if (in != NULL) {
- while (RUNE_EOF != (r = fgetrune(in)))
- buf_ins(buf, i++, r);
- fclose(in);
+ if (!strcmp(path,"-")) {
+ buf_ins(buf, 0, (Rune)'\n');
} else {
- buf_ins(buf, i, (Rune)'\n');
+ FMap file = fmap(path);
+ int chset = charset(file.buf, file.len);
+ if (chset > UTF_8) {
+ die("Unsupported character set");
+ } else if (chset == BINARY) {
+ for (size_t i = 0; i < file.len; i++)
+ buf_ins(buf, buf_end(buf), file.buf[i]);
+ } else { // UTF-8
+ for (size_t i = 0; i < file.len;) {
+ Rune r = 0;
+ size_t len = 0;
+ while (!utf8decode(&r, &len, file.buf[i++]));
+ buf_ins(buf, buf_end(buf), r);
+ }
+ }
+ funmap(file);
}
buf->insert_mode = false;
}
--- /dev/null
+#include "edit.h"
+
+static const struct {
+ int type;
+ int len;
+ char* seq;
+} BOMS[] = {
+ { .type = UTF_8, .len = 3, .seq = (char[]){ 0xEF, 0xBB, 0xBF }},
+ { .type = UTF_16BE, .len = 2, .seq = (char[]){ 0xFE, 0xFF }},
+ { .type = UTF_16LE, .len = 2, .seq = (char[]){ 0xFF, 0xFE }},
+ { .type = UTF_32BE, .len = 4, .seq = (char[]){ 0x00, 0x00, 0xFE, 0xFF }},
+ { .type = UTF_32LE, .len = 4, .seq = (char[]){ 0xFF, 0xFE, 0x00, 0x00 }},
+};
+
+static const char Utf8Valid[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+int charset(const char* buf, size_t len) {
+ /* look for a BOM and parse it */
+ for (size_t i = 0; i < (sizeof(BOMS)/sizeof(BOMS[0])); i++)
+ if (!strncmp(buf, BOMS[i].seq, BOMS[i].len))
+ return BOMS[i].type;
+ /* look for bytes that are invalid in utf-8 */
+ int type = UTF_8;
+ for (size_t i = 0; type && (i < len); i++)
+ type = Utf8Valid[(int)buf[i]];
+ return type;
+}
static void special_keys(Rune key) {
switch (key) {
- case KEY_F1: Buffer.insert_mode = !Buffer.insert_mode; break;
- case KEY_F6: ColorBase = !ColorBase; break;
- case KEY_LEFT: CursorPos = buf_byrune(&Buffer, CursorPos, -1); break;
- case KEY_RIGHT: CursorPos = buf_byrune(&Buffer, CursorPos, 1); break;
- case KEY_DOWN: CursorPos = buf_byline(&Buffer, CursorPos, 1); break;
- case KEY_UP: CursorPos = buf_byline(&Buffer, CursorPos, -1); break;
- case KEY_HOME: CursorPos = buf_bol(&Buffer, CursorPos); break;
- case KEY_END: CursorPos = buf_eol(&Buffer, CursorPos); break;
- case KEY_DELETE:
- if (Buffer.insert_mode)
- buf_del(&Buffer, CursorPos);
- break;
-
+ case KEY_F6: ColorBase = !ColorBase; break;
+ case KEY_UP: CursorPos = buf_byline(&Buffer, CursorPos, -1); break;
+ case KEY_DOWN: CursorPos = buf_byline(&Buffer, CursorPos, 1); break;
+ case KEY_LEFT: CursorPos = buf_byrune(&Buffer, CursorPos, -1); break;
+ case KEY_RIGHT: CursorPos = buf_byrune(&Buffer, CursorPos, 1); break;
+ case KEY_INSERT: Buffer.insert_mode = !Buffer.insert_mode; break;
+ case KEY_F1: Buffer.insert_mode = !Buffer.insert_mode; break;
+ case KEY_DELETE: buf_del(&Buffer, CursorPos); break;
+ case KEY_HOME: CursorPos = buf_bol(&Buffer, CursorPos); break;
+ case KEY_END: CursorPos = buf_eol(&Buffer, CursorPos); break;
}
}