From e12b94087df67d7834b17cc37eaa25586b59c3e3 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 23 Sep 2023 23:59:39 +0200 Subject: [PATCH] main3: basic functionality, array and string --- main3.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 main3.c diff --git a/main3.c b/main3.c new file mode 100644 index 0000000..b7f1344 --- /dev/null +++ b/main3.c @@ -0,0 +1,371 @@ +#include +#include +#include + +// Global defines + +#define STR_SIZE 128 +#define BUF_SIZE 1024*1024 + +// Memory + +static char g_memory[1024*1024]; +static int g_memory_index = 0; + +void * alloc(int num, int size) { + void * result = g_memory + g_memory_index; + for (int i = 0; i < num*size; i++) + g_memory[g_memory_index+i] = 0; + g_memory_index += num*size; + return result; +} + +#define NEW(TYPE) ((TYPE *)alloc(1, sizeof(TYPE))) +#define NEWARR(TYPE, NUM) ((TYPE *)alloc(NUM, sizeof(TYPE))) + +// getch + +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#include + +/* reads from keypress, doesn't echo */ +int getch(void) +{ + struct termios oldattr, newattr; + int ch; + tcgetattr( STDIN_FILENO, &oldattr ); + newattr = oldattr; + newattr.c_lflag &= ~( ICANON | ECHO ); // no ECHO for echo(?) + tcsetattr( STDIN_FILENO, TCSANOW, &newattr ); + ch = getchar(); + tcsetattr( STDIN_FILENO, TCSANOW, &oldattr ); + return ch; +} + +/* ungets keypress */ +void ungetch(int ch) +{ + struct termios oldattr, newattr; + tcgetattr( STDIN_FILENO, &oldattr ); + newattr = oldattr; + newattr.c_lflag &= ~( ICANON | ECHO ); + tcsetattr( STDIN_FILENO, TCSANOW, &newattr ); + ungetc(ch, stdin); + tcsetattr( STDIN_FILENO, TCSANOW, &oldattr ); +} +#endif + +int +peekch() { + int c = getch(); + ungetch(c); + return c; +} + +// VT100 + +#define ASCII_ESC 27 + +void vt100Escape(const char * str, ...) { + va_list args; + va_start(args, str); + + printf("%c", ASCII_ESC); + vprintf(str, args); +} + +void vt100ClearScreen() { vt100Escape("[2J"); } +void vt100CursorHome() { vt100Escape("[H"); } +void vt100CursorPos(int v, int h) { vt100Escape("[%d;%dH", v, h); } +void vt100SaveCursor() { vt100Escape("7"); } +void vt100RestoreCursor() { vt100Escape("8"); } +void vt100EnableAlternateBuffer() { vt100Escape("[?1049h"); } +void vt100DisableAlternateBuffer() { vt100Escape("[?1049l"); } +void vt100EnableNegative() { vt100Escape("[7m"); } +void vt100DisableNegative() { vt100Escape("[27m"); } +void vt100ShowCursor() { vt100Escape("[?25h"); } +void vt100HideCursor() { vt100Escape("[?25l"); } +void vt100GetScreenSize(int * v, int * h) { +#ifdef _WIN32 + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + *h = csbi.srWindow.Right - csbi.srWindow.Left + 1; + *v = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; +#else + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + *h = w.ws_row; + *v = w.ws_col; +#endif +} + +// Node + +typedef enum { + NK_Nul, + NK_Arr, + NK_Str, + + NK_COUNT +} NodeKind; + +typedef struct Node Node; +struct Node { + NodeKind kind; + void * data; + + int childCount; + Node *next, *prev, *parent, *child; +}; + +Node *NodeGetChild(Node *n, unsigned int index) { + if (index >= n->childCount) + return NULL; + + Node *result = n->child; + for (int i = 0; i < index; i++) + result = result->next; + return result; +} + +void NodeAppend(Node *n1, Node *n2) { + if (n1->childCount == 0) { + n1->child = n2; + } + else { + Node *lastChild = NodeGetChild(n1, n1->childCount-1); + + lastChild->next = n2; + n2->prev = lastChild; + n2->next = NULL; + } + n2->parent = n1; + n1->childCount += 1; +} + +void NodeInsert(Node *n1, Node *n2, unsigned int index) { + if (index >= n1->childCount-1) { + NodeAppend(n1, n2); + return; + } + + Node *insertAfter = NodeGetChild(n1, index); + Node *insertBefore = NodeGetChild(n1, index+1); + + insertAfter->next = n2; + insertBefore->prev = n2; + n2->prev = insertAfter; + n2->next = insertBefore; + + n1->childCount += 1; +} + +Node *NodeRemove(Node *n1, Node *n2) { + if (n1 == NULL) + return n2; + + Node *prev = n2->prev; + Node *next = n2->next; + + if (prev != NULL) + prev->next = next; + if (next != NULL) + next->prev = prev; + + n2->prev = n2->next = n2->parent = NULL; + + if (n2 == n1->child) + n1->child = next; + + n1->childCount -= 1; + + if (prev == NULL) + return n1; + else + return prev; +} + +void NodeDraw(Node *n, Node *selected) { + static int indent = 0; + for (int i = 0; i < indent; i++) + printf(" "); + + if (n == selected) vt100EnableNegative(); + + switch (n->kind) { + case NK_Nul: printf("null\n"); break; + case NK_Arr: printf("(%d) [\n", n->childCount); for (int i = 0; i < n->childCount; i++) NodeDraw(NodeGetChild(n, i), selected); printf("]\n"); break; + case NK_Str: printf("'%.16s'\n", (char *)n->data); break; + } + + if (n == selected) vt100DisableNegative(); +} + +// Input + +#define KEY_CTRL_C 3 +#define KEY_BACKSPACE1 8 +#define KEY_BACKSPACE2 127 + +typedef enum Input { + IN_None, + + IN_A, + IN_S, + IN_D, + + IN_H, + IN_J, + IN_K, + IN_L, + + IN_SPACE, + + IN_Quit, + + IN_COUNT +} Input; + +Input InputGet() { + int c; + + while (true) { + c = getch(); + switch (c) { + case 'a': return IN_A; + case 's': return IN_S; + case 'd': return IN_D; + + case 'h': return IN_H; + case 'j': return IN_J; + case 'k': return IN_K; + case 'l': return IN_L; + + case ' ': return IN_SPACE; + + case 'q': return IN_Quit; + } + } +} + +typedef enum InputAction { + IA_None, + IA_AppendArray, + IA_AppendString, + IA_StartEditing, + IA_Delete, + + IA_MoveLeft, + IA_MoveDown, + IA_MoveUp, + IA_MoveRight, + + IA_COUNT +} InputAction; + +Node *GetNode(InputAction actions[NK_COUNT][IN_COUNT]) { + Node * result = NEW(Node); + result->kind = NK_Arr; + + Node * n = result; + + Input in; + InputAction action; + + enum { + Mode_Normal, + Mode_Editing, + } mode = Mode_Normal; + + while (true) { + vt100ClearScreen(); + vt100CursorHome(); + NodeDraw(result, n); + + if (mode == Mode_Editing) { + int c = getch(); + char *s = (char*)n->data; + int slen = strlen(s); + + if (c == KEY_BACKSPACE1 || c == KEY_BACKSPACE2) { + s[slen-1] = '\0'; + } + else if (c == 13) { + mode = Mode_Normal; + } + else if (slen < STR_SIZE) { + s[slen++] = (char)c; + } + } + else if (mode == Mode_Normal) { + in = InputGet(); + + if (in == IN_Quit) + break; + + action = actions[n->kind][in]; + + #define NODE_APPEND(KIND, DATA) Node *newNode = NEW(Node); newNode->kind = KIND; newNode->data = DATA; NodeAppend(n, newNode); n = newNode; + + switch (action) { + case IA_AppendArray: { NODE_APPEND(NK_Arr, 0); break; } + case IA_AppendString: { NODE_APPEND(NK_Str, NEWARR(char, STR_SIZE)); mode = Mode_Editing; break; } + case IA_StartEditing: { mode = Mode_Editing; break; } + case IA_Delete: { n = NodeRemove(n->parent, n); break; } + + case IA_MoveLeft: { if (n->prev != NULL) n = n->prev; break; } + case IA_MoveDown: { if (n->child != NULL) n = n->child; break; } + case IA_MoveUp: { if (n->parent != NULL) n = n->parent; break; } + case IA_MoveRight: { if (n->next != NULL) n = n->next; break; } + } + + #undef NODE_APPEND + } + } + + return result; +} + + +int main() { + // Setup + InputAction actions[NK_COUNT][IN_COUNT]; + + actions[NK_Arr][IN_A] = IA_AppendArray; + actions[NK_Arr][IN_S] = IA_AppendString; + actions[NK_Arr][IN_D] = IA_Delete; + actions[NK_Arr][IN_H] = IA_MoveLeft; + actions[NK_Arr][IN_J] = IA_MoveDown; + actions[NK_Arr][IN_K] = IA_MoveUp; + actions[NK_Arr][IN_L] = IA_MoveRight; + + actions[NK_Str][IN_SPACE] = IA_StartEditing; + actions[NK_Str][IN_D] = IA_Delete; + actions[NK_Str][IN_H] = IA_MoveLeft; + actions[NK_Str][IN_J] = IA_MoveDown; + actions[NK_Str][IN_K] = IA_MoveUp; + actions[NK_Str][IN_L] = IA_MoveRight; + + // Main + vt100EnableAlternateBuffer(); + vt100HideCursor(); + + Node *n = GetNode(actions); + + vt100DisableAlternateBuffer(); + vt100ShowCursor(); + + int v, h; + vt100GetScreenSize(&v, &h); + printf("Screen Size: %d | %d\n", v, h); + + NodeDraw(n, NULL); + + return 0; +} -- 2.50.1