summaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/buffer.cpp45
-rw-r--r--src/server/client.cpp93
-rw-r--r--src/server/page.cpp87
-rw-r--r--src/server/point.cpp139
4 files changed, 364 insertions, 0 deletions
diff --git a/src/server/buffer.cpp b/src/server/buffer.cpp
new file mode 100644
index 0000000..7b4c92d
--- /dev/null
+++ b/src/server/buffer.cpp
@@ -0,0 +1,45 @@
+struct Buffer {
+ const char *name;
+ Page *storage;
+
+ Buffer(const char *name) : name(name), storage(new Page()) {}
+
+ void free_storage() {
+ while (storage) {
+ Page *iter = storage;
+ storage = storage->next;
+ delete iter;
+ }
+ }
+
+ void read_file(const char *pathname) {
+ free_storage();
+ int file = open(pathname, O_RDONLY);
+ storage = new Page();
+ int bytes_read = read(file, storage->elements, PAGE_SIZE);
+ Page *iter = storage;
+ while (bytes_read > 0) {
+ iter->gap_start = bytes_read;
+ iter->element_count = bytes_read;
+ iter->next = new Page();
+ iter->next->prev = iter;
+ iter = iter->next;
+ bytes_read = read(file, iter->elements, PAGE_SIZE);
+ }
+ if (iter->element_count == 0) {
+ delete iter;
+ }
+ close(file);
+ }
+
+ void write_file(const char *pathname) {
+ int file = open(pathname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ Page *iter = storage;
+ while (iter) {
+ write(file, iter->elements, iter->gap_start);
+ write(file, iter->elements + iter->gap_end, PAGE_SIZE - iter->gap_end);
+ iter = iter->next;
+ }
+ close(file);
+ }
+};
diff --git a/src/server/client.cpp b/src/server/client.cpp
new file mode 100644
index 0000000..bed62c5
--- /dev/null
+++ b/src/server/client.cpp
@@ -0,0 +1,93 @@
+#define MAX_MSG_SIZE 128
+#define pos(x, y) (x) + (y) * window_w
+
+struct Client {
+ int sockfd;
+ Point cursor;
+ Point window_start;
+
+ Client(const Buffer &b) : cursor(b), window_start(cursor) {}
+
+ void parse_message() {
+ int8_t message[MAX_MSG_SIZE] = {};
+ read(sockfd, message, MAX_MSG_SIZE - 1);
+ int8_t *iter = message;
+ while (*iter) {
+ switch (*iter) {
+ case OP_MOVE1:
+ move(iter[1]);
+ iter += 2;
+ break;
+ case OP_MOVE2:
+ move(decode2(iter, 1));
+ iter += 3;
+ break;
+ case OP_MOVE4:
+ move(decode4(iter, 1));
+ iter += 5;
+ break;
+ case OP_MOVE8:
+ move(decode8(iter, 1));
+ iter += 9;
+ break;
+ case OP_INSERT:
+ push(iter[1]);
+ iter += 2;
+ break;
+ case OP_DELETE:
+ pop();
+ iter += 1;
+ break;
+ case OP_SHOW:
+ show(decode2(iter, 1), decode2(iter, 3));
+ iter += 6;
+ break;
+ }
+ }
+ }
+
+ void show(size_t window_w, size_t window_h) {
+ char *view = new char[window_w * window_h];
+
+ Point window_end(window_start);
+ for (int i = 0; i < window_h; i++) {
+ for (int j = 0; j < window_w; j++) {
+ view[pos(j, i)] = window_end.element();
+ if (window_end.element() == '\n') {
+ for (int k = j + 1; k < window_w; k++) {
+ view[pos(k, i)] = 0;
+ }
+ j = window_w;
+ } else if (window_end.element() == '\t') {
+ for (int k = j + 1; k < j + 8; k++) {
+ view[pos(k, i)] = 0;
+ }
+ j = j + 7;
+ }
+ window_end++;
+ }
+ }
+
+ write(sockfd, view, window_w * window_h);
+ delete[] view;
+ }
+
+ void move(int64_t target) {
+ while (target > 0) {
+ cursor++;
+ target--;
+ }
+ while (target < 0) {
+ cursor--;
+ target++;
+ }
+ }
+
+ void push(int8_t input) {
+ cursor.push(input);
+ }
+
+ void pop() {
+ cursor.pop();
+ }
+};
diff --git a/src/server/page.cpp b/src/server/page.cpp
new file mode 100644
index 0000000..77cf686
--- /dev/null
+++ b/src/server/page.cpp
@@ -0,0 +1,87 @@
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+struct Page {
+ uint8_t *elements;
+ Page *next;
+ Page *prev;
+ uint16_t gap_start;
+ uint16_t gap_end;
+ uint16_t element_count;
+
+ Page() {
+ elements = new uint8_t[PAGE_SIZE];
+ gap_start = 0;
+ gap_end = PAGE_SIZE;
+ element_count = 0;
+ next = nullptr;
+ prev = nullptr;
+ }
+
+ ~Page() {
+ if (prev) prev->next = next;
+ if (next) next->prev = prev;
+ delete[] elements;
+ }
+
+ void split() {
+ Page *front = new Page();
+
+ memcpy(front->elements, elements + PAGE_SIZE / 2, PAGE_SIZE / 2);
+
+ front->gap_start = PAGE_SIZE / 2;
+ front->gap_end = PAGE_SIZE;
+ front->element_count = PAGE_SIZE / 2;
+
+ gap_start = PAGE_SIZE / 2;
+ gap_end = PAGE_SIZE;
+ element_count = PAGE_SIZE / 2;
+
+ if (next) {
+ next->prev = front;
+ }
+ front->next = next;
+ front->prev = this;
+ next = front;
+ }
+
+ void copy_to(Page *dest) {
+ memcpy(dest->elements, elements, PAGE_SIZE);
+ dest->gap_start = gap_start;
+ dest->gap_end = gap_end;
+ dest->element_count = element_count;
+ }
+
+ void move_gap_forward() {
+ elements[gap_start] = elements[gap_end];
+ gap_start++;
+ gap_end++;
+ }
+
+ void move_gap_backward() {
+ gap_end--;
+ gap_start--;
+ elements[gap_end] = elements[gap_start];
+ }
+
+ void push(uint8_t c) {
+ elements[gap_start] = c;
+ gap_start++;
+ element_count++;
+ }
+
+ void pop() {
+ gap_start--;
+ element_count--;
+ }
+
+ bool is_empty() {
+ return element_count == 0;
+ }
+
+ bool is_full() {
+ return gap_start == gap_end;
+ }
+
+};
diff --git a/src/server/point.cpp b/src/server/point.cpp
new file mode 100644
index 0000000..ab9f70f
--- /dev/null
+++ b/src/server/point.cpp
@@ -0,0 +1,139 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+struct Point {
+ Page *page;
+ uint16_t index;
+
+ uint16_t index_to_offset() {
+ if (index < page->gap_start) {
+ return index;
+ } else {
+ return index + (page->gap_end - page->gap_start);
+ }
+ }
+
+ uint8_t prev_byte() {
+ if (index == 0) {
+ if (page->prev) {
+ return page->prev->elements[Point(page->prev, page->prev->element_count - 1).index_to_offset()];
+ } else {
+ return 0;
+ }
+ } else {
+ return page->elements[Point(page, index - 1).index_to_offset()];
+ }
+ }
+
+ uint8_t next_byte() {
+ if (index == page->element_count) {
+ if (page->next) {
+ return page->next->elements[Point(page->next, 0).index_to_offset()];
+ } else {
+ return 0;
+ }
+ } else {
+ return page->elements[index_to_offset()];
+ }
+ }
+
+ void move_forward() {
+ if (index < page->element_count) {
+ index++;
+ } else if (page->next) {
+ page = page->next;
+ index = 0;
+ }
+ }
+
+ void move_backward() {
+ if (index > 0) {
+ index--;
+ } else if (page->prev) {
+ page = page->prev;
+ index = page->element_count;
+ }
+ }
+
+
+ public:
+
+ Point() : page(0), index(0) {}
+ Point(Page* page, uint16_t index) : page(page), index(index) {}
+ Point(const Buffer &b) : page(b.storage), index(0) {}
+ Point(const Point &p) : page(p.page), index(p.index) {}
+
+ bool operator==(Point p) {
+ return page == p.page && index == p.index;
+ }
+
+ bool operator!=(Point p) {
+ return page != p.page || index != p.index;
+ }
+
+ bool at_start() {
+ return index == 0 && !page->prev;
+ }
+
+ bool at_end() {
+ return index == page->element_count && !page->next;
+ }
+
+ void operator++(int) {
+ if (index == page->element_count) move_forward();
+ move_forward();
+ }
+
+ void operator--(int) {
+ move_backward();
+ if (index == 0) move_backward();
+ }
+
+ char element() {
+ return next_byte();
+ }
+
+ void align_gap() {
+ while (page->gap_end < index_to_offset()) {
+ page->move_gap_forward();
+ }
+ while (page->gap_end > index_to_offset()) {
+ page->move_gap_backward();
+ }
+ }
+
+ void push(uint8_t c) {
+ if (page->is_full()) {
+ page->split();
+ if (index >= PAGE_SIZE / 2) {
+ page = page->next;
+ index -= PAGE_SIZE / 2;
+ }
+ }
+ align_gap();
+ page->push(c);
+ move_forward();
+ }
+
+ void pop() {
+ if (!at_start()) {
+ align_gap();
+ page->pop();
+ move_backward();
+ if (index == 0) {
+ move_backward();
+ }
+ }
+ if (page->is_empty()) {
+ if (page->prev) {
+ move_backward();
+ delete page->next;
+ } else if (page->next) {
+ page->next->copy_to(page);
+ delete page->next;
+ index = 0;
+ }
+ }
+ }
+
+};