From d608bef678fa97b3af910fa62598c55f33650825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Tom=C3=A1s?= Date: Fri, 17 Jul 2020 16:23:43 -0300 Subject: Restructure source files --- .gitignore | 2 +- Makefile | 10 ++-- buffer.cpp | 45 ---------------- client.cpp | 93 --------------------------------- ipc.cpp | 40 --------------- jet.cpp | 72 -------------------------- jet2.cpp | 118 ------------------------------------------ page.cpp | 87 ------------------------------- point.cpp | 139 -------------------------------------------------- src/client/cursor.cpp | 13 +++++ src/client/window.cpp | 16 ++++++ src/common/ipc.cpp | 40 +++++++++++++++ src/jet.cpp | 72 ++++++++++++++++++++++++++ src/jetc.cpp | 98 +++++++++++++++++++++++++++++++++++ src/server/buffer.cpp | 45 ++++++++++++++++ src/server/client.cpp | 93 +++++++++++++++++++++++++++++++++ src/server/page.cpp | 87 +++++++++++++++++++++++++++++++ src/server/point.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ 18 files changed, 609 insertions(+), 600 deletions(-) delete mode 100644 buffer.cpp delete mode 100644 client.cpp delete mode 100644 ipc.cpp delete mode 100644 jet.cpp delete mode 100644 jet2.cpp delete mode 100644 page.cpp delete mode 100644 point.cpp create mode 100644 src/client/cursor.cpp create mode 100644 src/client/window.cpp create mode 100644 src/common/ipc.cpp create mode 100644 src/jet.cpp create mode 100644 src/jetc.cpp create mode 100644 src/server/buffer.cpp create mode 100644 src/server/client.cpp create mode 100644 src/server/page.cpp create mode 100644 src/server/point.cpp diff --git a/.gitignore b/.gitignore index a73d53b..efbd2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ jet -jet2 +jetc diff --git a/Makefile b/Makefile index be67256..7ead0a1 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ FLAGS=-ggdb -O0 _PHONY=all -all:jet jet2 +all:jet jetc -jet: Makefile *.cpp - g++ $(FLAGS) jet.cpp -o jet +jet: Makefile src/jet.cpp src/server/*.cpp src/common/*.cpp + g++ $(FLAGS) src/jet.cpp -o $@ -jet2: Makefile *.cpp - g++ $(FLAGS) jet2.cpp -o jet2 $(shell pkg-config --cflags --libs ncurses) +jetc: Makefile src/jetc.cpp src/client/*.cpp src/common/*.cpp + g++ $(FLAGS) src/jetc.cpp -o $@ $(shell pkg-config --cflags --libs ncurses) diff --git a/buffer.cpp b/buffer.cpp deleted file mode 100644 index 7b4c92d..0000000 --- a/buffer.cpp +++ /dev/null @@ -1,45 +0,0 @@ -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/client.cpp b/client.cpp deleted file mode 100644 index bed62c5..0000000 --- a/client.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#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/ipc.cpp b/ipc.cpp deleted file mode 100644 index 7d46307..0000000 --- a/ipc.cpp +++ /dev/null @@ -1,40 +0,0 @@ -enum Operation { - OP_NULL = 0, - OP_MOVE1, - OP_MOVE2, - OP_MOVE4, - OP_MOVE8, - OP_INSERT, - OP_DELETE, - OP_SHOW -}; - -void encode2(int16_t data, int8_t *message, size_t offset) { - message[offset] = data & 0x00ff; - message[offset + 1] = (data & 0xff00) >> 8; -} - -int16_t decode2(int8_t *message, size_t offset) { - return (int16_t)message[offset + 1] << 8 & 0xff00 - | (int16_t)message[offset] & 0x00ff; -} - -void encode4(int32_t data, int8_t *message, size_t offset) { - encode2( data & 0x0000ffff, message, offset); - encode2((data & 0xffff0000) >> 16, message, offset + 2); -} - -int32_t decode4(int8_t *message, size_t offset) { - return (int32_t)decode2(message, offset + 2) << 16 & 0xffff0000 - | (int32_t)decode2(message, offset) & 0x0000ffff; -} - -void encode8(int64_t data, int8_t *message, size_t offset) { - encode4( data & 0x00000000ffffffff, message, offset); - encode4((data & 0xffffffff00000000) >> 32, message, offset + 4); -} - -int64_t decode8(int8_t *message, size_t offset) { - return (int64_t)decode4(message, offset + 4) << 32 & 0xffffffff00000000 - | (int64_t)decode4(message, offset) & 0x00000000ffffffff; -} diff --git a/jet.cpp b/jet.cpp deleted file mode 100644 index 2006a77..0000000 --- a/jet.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ipc.cpp" -#include "page.cpp" -#include "buffer.cpp" -#include "point.cpp" -#include "client.cpp" - -#define PORT 6969 -#define MAX_EVENTS 10 - -int create_listener() { - int s = socket(AF_INET, SOCK_STREAM, 0); - sockaddr_in addr = { AF_INET, htons(PORT), htonl(INADDR_LOOPBACK)}; - int opt = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); - bind(s, (sockaddr *) &addr, sizeof(sockaddr_in)); - listen(s, MAX_EVENTS); - return s; -} - -int main() { - Buffer scratch("scratch"); - scratch.read_file("LICENSE"); - - int listener = create_listener(); - - int epollfd = epoll_create1(0); - - epoll_event ev; - ev.events = EPOLLIN; - ev.data.fd = listener; - epoll_ctl(epollfd, EPOLL_CTL_ADD, listener, &ev); - - epoll_event events[MAX_EVENTS]; - Client *clients[1024] = {}; - - while (true) { - int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); - - for (int i = 0; i < nfds; i++) { - if (events[i].data.fd == listener) { - int clientfd = accept(listener, 0, 0); - ev.events = EPOLLIN | EPOLLET; - ev.data.fd = clientfd; - if (clients[clientfd]) { - delete clients[clientfd]; - } - Client *c = new Client(scratch); - c->sockfd = clientfd; - clients[clientfd] = c; - epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev); - } else { - clients[events[i].data.fd]->parse_message(); - } - } - } - - close(listener); -} diff --git a/jet2.cpp b/jet2.cpp deleted file mode 100644 index 9fb4027..0000000 --- a/jet2.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ipc.cpp" - -#define NORMAL_MODE 0 -#define INSERT_MODE 1 -#define PORT 6969 -#define pos(x, y) (x) + (y) * window_width - -int main(int argc, char *argv[]) { - initscr(); - cbreak(); - noecho(); - intrflush(stdscr, FALSE); - keypad(stdscr, TRUE); - - int window_height, window_width; - getmaxyx(stdscr, window_height, window_width); - - char *view = new char[window_width * window_height]; - for (int i = 0; i < window_width * window_height; view[i++] = 0); - - int s = socket(AF_INET, SOCK_STREAM, 0); - sockaddr_in addr = { AF_INET, htons(PORT), htonl(INADDR_LOOPBACK)}; - connect(s, (sockaddr *) &addr, sizeof(sockaddr_in)); - - int mode = NORMAL_MODE; - int cursor_x = 0; - int cursor_y = 0; - - int quit = 0; - while (!quit) { - clear(); - - int8_t msg[5]; - msg[0] = OP_SHOW; - encode2(window_width, msg, 1); - encode2(window_height, msg, 3); - write(s, msg, 5); - read(s, view, window_width * window_height); - for (int i = 0; i < window_width * window_height; i++) { - printw("%c", view[i]); - } - move(cursor_y, cursor_x); - - int8_t mov[2]; - int8_t del[1]; - int8_t ins[2]; - int input = getch(); - if (mode == NORMAL_MODE) { - switch (input) { - case '': - quit = 1; - break; - case 'i': - mode = INSERT_MODE; - break; - case 'h': - mov[0] = OP_MOVE1; - mov[1] = -1; - write(s, mov, 2); - do { - if (cursor_x <= 0) { - if (cursor_y > 0) { - cursor_x = window_width - 1; - cursor_y--; - } - } else { - cursor_x--; - } - } while (view[pos(cursor_x, cursor_y)] == 0); - break; - case 'l': - mov[0] = OP_MOVE1; - mov[1] = 1; - write(s, mov, 2); - do { - if (cursor_x >= window_width - 1) { - if (cursor_y < window_height - 1) { - cursor_x = 0; - cursor_y++; - } else { - break; - } - } else { - cursor_x++; - } - } while (view[pos(cursor_x, cursor_y)] == 0); - break; - } - } else { - switch (input) { - case '': - mode = NORMAL_MODE; - break; - case KEY_BACKSPACE: - del[0] = OP_DELETE; - write(s, del, 1); - break; - default: - ins[0] = OP_INSERT; - ins[1] = input; - write(s, ins, 2); - } - } - } - - endwin(); - return 0; -} diff --git a/page.cpp b/page.cpp deleted file mode 100644 index 77cf686..0000000 --- a/page.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#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/point.cpp b/point.cpp deleted file mode 100644 index ab9f70f..0000000 --- a/point.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include - -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; - } - } - } - -}; diff --git a/src/client/cursor.cpp b/src/client/cursor.cpp new file mode 100644 index 0000000..4e76151 --- /dev/null +++ b/src/client/cursor.cpp @@ -0,0 +1,13 @@ +struct Cursor { + int x; + int y; + Window *w; + + void move_left() { + if (x > 0) x--; + } + + void move_right() { + if (x < w->width - 1 && w->pos(x + 1, y) != 0) x++; + } +}; diff --git a/src/client/window.cpp b/src/client/window.cpp new file mode 100644 index 0000000..e718e63 --- /dev/null +++ b/src/client/window.cpp @@ -0,0 +1,16 @@ +struct Window { + char *view; + int width; + int height; + + void init() { + view = new char[width * height]; + for (int i = 0; i < width * height; i++) { + view[i] = 0; + } + } + + char pos(size_t x, size_t y) { + return view[x + y * width]; + } +}; diff --git a/src/common/ipc.cpp b/src/common/ipc.cpp new file mode 100644 index 0000000..7d46307 --- /dev/null +++ b/src/common/ipc.cpp @@ -0,0 +1,40 @@ +enum Operation { + OP_NULL = 0, + OP_MOVE1, + OP_MOVE2, + OP_MOVE4, + OP_MOVE8, + OP_INSERT, + OP_DELETE, + OP_SHOW +}; + +void encode2(int16_t data, int8_t *message, size_t offset) { + message[offset] = data & 0x00ff; + message[offset + 1] = (data & 0xff00) >> 8; +} + +int16_t decode2(int8_t *message, size_t offset) { + return (int16_t)message[offset + 1] << 8 & 0xff00 + | (int16_t)message[offset] & 0x00ff; +} + +void encode4(int32_t data, int8_t *message, size_t offset) { + encode2( data & 0x0000ffff, message, offset); + encode2((data & 0xffff0000) >> 16, message, offset + 2); +} + +int32_t decode4(int8_t *message, size_t offset) { + return (int32_t)decode2(message, offset + 2) << 16 & 0xffff0000 + | (int32_t)decode2(message, offset) & 0x0000ffff; +} + +void encode8(int64_t data, int8_t *message, size_t offset) { + encode4( data & 0x00000000ffffffff, message, offset); + encode4((data & 0xffffffff00000000) >> 32, message, offset + 4); +} + +int64_t decode8(int8_t *message, size_t offset) { + return (int64_t)decode4(message, offset + 4) << 32 & 0xffffffff00000000 + | (int64_t)decode4(message, offset) & 0x00000000ffffffff; +} diff --git a/src/jet.cpp b/src/jet.cpp new file mode 100644 index 0000000..6cc4470 --- /dev/null +++ b/src/jet.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/ipc.cpp" +#include "server/page.cpp" +#include "server/buffer.cpp" +#include "server/point.cpp" +#include "server/client.cpp" + +#define PORT 6969 +#define MAX_EVENTS 10 + +int create_listener() { + int s = socket(AF_INET, SOCK_STREAM, 0); + sockaddr_in addr = { AF_INET, htons(PORT), htonl(INADDR_LOOPBACK)}; + int opt = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); + bind(s, (sockaddr *) &addr, sizeof(sockaddr_in)); + listen(s, MAX_EVENTS); + return s; +} + +int main() { + Buffer scratch("scratch"); + scratch.read_file("test.txt"); + + int listener = create_listener(); + + int epollfd = epoll_create1(0); + + epoll_event ev; + ev.events = EPOLLIN; + ev.data.fd = listener; + epoll_ctl(epollfd, EPOLL_CTL_ADD, listener, &ev); + + epoll_event events[MAX_EVENTS]; + Client *clients[1024] = {}; + + while (true) { + int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); + + for (int i = 0; i < nfds; i++) { + if (events[i].data.fd == listener) { + int clientfd = accept(listener, 0, 0); + ev.events = EPOLLIN | EPOLLET; + ev.data.fd = clientfd; + if (clients[clientfd]) { + delete clients[clientfd]; + } + Client *c = new Client(scratch); + c->sockfd = clientfd; + clients[clientfd] = c; + epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &ev); + } else { + clients[events[i].data.fd]->parse_message(); + } + } + } + + close(listener); +} diff --git a/src/jetc.cpp b/src/jetc.cpp new file mode 100644 index 0000000..9650eb6 --- /dev/null +++ b/src/jetc.cpp @@ -0,0 +1,98 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common/ipc.cpp" +#include "client/window.cpp" +#include "client/cursor.cpp" + +#define NORMAL_MODE 0 +#define INSERT_MODE 1 +#define PORT 6969 + +int main(int argc, char *argv[]) { + initscr(); + cbreak(); + noecho(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + Window window; + getmaxyx(stdscr, window.height, window.width); + window.init(); + + int s = socket(AF_INET, SOCK_STREAM, 0); + sockaddr_in addr = { AF_INET, htons(PORT), htonl(INADDR_LOOPBACK) }; + connect(s, (sockaddr *) &addr, sizeof(sockaddr_in)); + + int mode = NORMAL_MODE; + Cursor cursor = { 0, 0, &window }; + + int quit = 0; + while (!quit) { + clear(); + + int8_t msg[5]; + msg[0] = OP_SHOW; + encode2(window.width, msg, 1); + encode2(window.height, msg, 3); + write(s, msg, 5); + read(s, window.view, window.width * window.height); + for (int i = 0; i < window.width * window.height; i++) { + printw("%c", window.view[i]); + } + move(cursor.y, cursor.x); + + int8_t mov[2]; + int8_t del[1]; + int8_t ins[2]; + int input = getch(); + if (mode == NORMAL_MODE) { + switch (input) { + case '': + quit = 1; + break; + case 'i': + mode = INSERT_MODE; + break; + case 'h': + mov[0] = OP_MOVE1; + mov[1] = -1; + write(s, mov, 2); + cursor.move_left(); + break; + case 'l': + mov[0] = OP_MOVE1; + mov[1] = 1; + write(s, mov, 2); + cursor.move_right(); + break; + } + } else { + switch (input) { + case '': + mode = NORMAL_MODE; + break; + case KEY_BACKSPACE: + del[0] = OP_DELETE; + write(s, del, 1); + break; + default: + ins[0] = OP_INSERT; + ins[1] = input; + write(s, ins, 2); + } + } + } + + close(s); + + endwin(); + return 0; +} 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 +#include + +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; + } + } + } + +}; -- cgit v1.2.3