commit ce12bebb7856ec997c78a4254153b4aabd3b2445 Author: Maciej Samborski Date: Mon Feb 12 00:04:10 2024 +0100 Getting started diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0421292 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +valgrind-out.txt +Makefile +main diff --git a/da.h b/da.h new file mode 100644 index 0000000..89838fa --- /dev/null +++ b/da.h @@ -0,0 +1,156 @@ +#ifndef DA_H_ +#define DA_H_ + +#include +#include +#include +#include + +enum daFields { + SIZE = 0, + CAPACITY = 1, + TYPE = 2, + DATA = 3, +}; + +typedef void * dynarr; +dynarr _daCreate(size_t initCapacity, size_t type, size_t size); +dynarr _daPush(dynarr da, void * item); +void _daPop(dynarr da, void * element); +void daPopDiscard(dynarr da); +void daFree(dynarr da); + +size_t daSize(dynarr da); +size_t daCap(dynarr da); +size_t daType(dynarr da); + +size_t * daField(dynarr da, enum daFields field); +void * daGetRef(dynarr da, size_t index); + +typedef void(* func)(void * item); +void daForeach(dynarr da, func f); + +typedef char * heapstr; +heapstr daToCStr(dynarr da); +void daBzero(dynarr da); + +#define dynarr(type) type * +#define daCreate(type, cap) _daCreate(cap, sizeof(type), 0) +#define daPush(da, item) da = _daPush(da, &item) +#define daPop(da, item) _daPop(da, &item) + +#endif // DA_H_ + +#ifdef DA_IMPLEMENTATION + +dynarr _daCreate(size_t cap, size_t type, size_t size) +{ + size_t * da = (size_t *) malloc(type * cap + DATA * sizeof(size_t)); + da[SIZE] = size; + da[CAPACITY] = cap; + da[TYPE] = type; + + return (dynarr) (da + DATA); +} + +void daFree(dynarr da) +{ + free((size_t *) da - DATA); +} + +dynarr daCopy(dynarr da) +{ + dynarr temp = _daCreate(daCap(da), daType(da), daSize(da)); + memcpy(temp, da, daSize(da) * daType(da)); + return temp; +} + +dynarr daResize(dynarr da) +{ + dynarr temp = _daCreate(daCap(da) * 2, daType(da), daSize(da)); + memcpy(temp, da, daSize(da) * daType(da)); + daFree(da); + return temp; +} + +dynarr _daPush(dynarr da, void * item) +{ + if (daSize(da) >= daCap(da)) da = daResize(da); + memcpy((char *)da + daSize(da) * daType(da), item, daType(da)); + *daField(da, SIZE) += 1; + return da; +} + +void _daPop(dynarr da, void * elem) +{ + *daField(da, SIZE) -= 1; + memcpy(elem, (char *)da + daSize(da) * daType(da), daType(da)); +} + +void daPopDiscard(dynarr da) +{ + *daField(da, SIZE) -= 1; +} + +size_t * daField(dynarr da, enum daFields field) +{ + if (field < SIZE || field > TYPE) + { + fprintf(stderr, "*------------------------------*\n"); + fprintf(stderr, "ERROR: Wrong field: %d\n", field); + fprintf(stderr, "AVAILABLE: SIZE, CAPACITY, TYPE\n"); + fprintf(stderr, "*------------------------------*\n"); + exit(1); + } + + return ((size_t *) da - DATA + field); +} + +size_t daSize(dynarr da) +{ + return ((size_t *) da - DATA)[SIZE]; +} + +size_t daCap(dynarr da) +{ + return ((size_t *) da - DATA)[CAPACITY]; +} + +size_t daType(dynarr da) +{ + return ((size_t *) da - DATA)[TYPE]; +} + +void daForeach(dynarr da, func f) +{ + for (size_t i = 0; i < daSize(da); ++i) + f((char *) da + i * daType(da)); +} + +heapstr daToCStr(dynarr da) +{ + char * buffer = (char *) calloc(1, daSize(da) + 1); + memcpy(buffer, da, daSize(da) * daType(da)); + return buffer; +} + +void daBzero(dynarr da) +{ + memset(da, '\0', daCap(da)); + *daField(da, SIZE) = 0; +} + +void * daGetRef(dynarr da, size_t index) +{ + if (index >= daSize(da)) + { + fprintf(stderr, "*------------------------------*\n"); + fprintf(stderr, "ERROR: Access out of bounds\n"); + fprintf(stderr, "*------------------------------*\n"); + exit(1); + } + + return (void *)((char *)da + index * daType(da)); +} + +#endif // DA_IMPLEMENTATION diff --git a/main.c b/main.c new file mode 100644 index 0000000..3e29d3c --- /dev/null +++ b/main.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "term.h" + +#define DA_IMPLEMENTATION +#include "da.h" + +#define bufferLen 256 +#define PORT 12123 + +enum { + SENDER = 0, + RECEIVER = 1, + THREAD_COUNT = 2, +}; + +typedef int fd_t; + +void * sender(void * arg) +{ + fd_t * connFd = arg; + + return NULL; +} + +void * receiver(void * arg) +{ + char buffer[bufferLen] = {0}; + + fd_t * connFd = arg; + + while (1) + { + read(*connFd, buffer, bufferLen); + printf("\033[A"); + printf("\n"); + printf("%s", buffer); + if (strcmp(buffer, "e\n") == 0) break; + + bzero(buffer, bufferLen); + } + + return NULL; +} + +void serve() +{ + int sockFd, connFd; + struct sockaddr_in server, client; + bzero(&server, sizeof(server)); + bzero(&client, sizeof(client)); + + sockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockFd < 0) + { + fprintf(stderr, "ERROR:%d:%s\n", errno, strerror(errno)); + exit(1); + } + + server.sin_family = AF_INET; + server.sin_addr.s_addr = inet_addr("0.0.0.0"); + server.sin_port = htons(PORT); + + if (bind(sockFd, (struct sockaddr *) &server, sizeof(server)) < 0) + { + fprintf(stderr, "ERROR:%d:%s\n", errno, strerror(errno)); + exit(1); + } + + if (listen(sockFd, 0) < 0) + { + fprintf(stderr, "ERROR:%d:%s\n", errno, strerror(errno)); + exit(1); + } + + socklen_t len = sizeof(client); + connFd = accept(sockFd, (struct sockaddr *) &client, &len); + if (connFd < 0) + { + fprintf(stderr, "ERROR:%d:%s\n", errno, strerror(errno)); + exit(1); + } + + pthread_t threads[THREAD_COUNT]; + int threadError = 0; + + threadError = pthread_create(&threads[SENDER], NULL, sender, &connFd); + if (threadError) + { + fprintf(stderr, "ERROR:Couldn't create SENDER Thread\n"); + exit(1); + } + + threadError = pthread_create(&threads[RECEIVER], NULL, receiver, &connFd); + if (threadError) + { + fprintf(stderr, "ERROR:Couldn't create RECEIVER Thread\n"); + exit(1); + } + + for (size_t i = 0; i < THREAD_COUNT; ++i) + pthread_join(threads[i], NULL); + + close(sockFd); +} + +typedef struct State { + Term term; + dynarr(char *) messages; +} State; + +void draw(State * state) +{ + int x, y; + getmaxyx(stdscr, y, x); + if (state->term.termX != x || + state->term.termY != y) + { + recreateWindows(&state->term); + } + + wmove(state->term.chat, 1, 2); + wmove(state->term.input, state->term.inputY, state->term.inputX); + + for (size_t i = 0; i < daSize(state->messages); ++i) + { + wprintw(state->term.chat, "%s", state->messages[i]); + wmove(state->term.chat, 2 + i, 2); + } + + wrefresh(state->term.chat); + wrefresh(state->term.extra); + wrefresh(state->term.input); +} + +void loop(State * state) +{ + initNcurses(); + + state->term = createTerm(); + draw(state); + + dynarr(char) buffer = daCreate(char, 128); + heapstr msg = NULL; + + int key = 0; + while ((key = getch()) != 27 /* ESC */) + { + switch (key) + { + case 10: /* ENTER */ + msg = daToCStr(buffer); + daPush(state->messages, msg); + daBzero(buffer); + state->term.inputX = 1; + + for (size_t i = 1; i < getmaxx(state->term.input) - 1; ++i) + mvwprintw(state->term.input, state->term.inputY, i, " "); + + break; + + case KEY_LEFT: + if (state->term.inputX > 1) + state->term.inputX -= 1; + break; + + case KEY_RIGHT: + if (state->term.inputX < getmaxx(state->term.input) - 2) + state->term.inputX += 1; + break; + + case KEY_UP: + case KEY_DOWN: + break; + + case KEY_BACKSPACE: + if (state->term.inputX > 1) + { + state->term.inputX -= 1; + wmove(state->term.input, state->term.inputY, state->term.inputX); + wprintw(state->term.input, " "); + + if (daSize(buffer)) + daPopDiscard(buffer); + } + break; + + case KEY_F(1): + recreateWindows(&state->term); + break; + + case 410: /* F11 */ + break; + + default: + if (state->term.inputX < getmaxx(state->term.input) - 2) + { + wprintw(state->term.input, "%c", key); + daPush(buffer, key); + state->term.inputX += 1; + } + } + + draw(state); + } + + deinitNcurses(); + daFree(buffer); +} + +int main(void) +{ + State state = { + .term = { }, + .messages = daCreate(char *, 64), + }; + + loop(&state); + + for (size_t i = 0; i < daSize(state.messages); ++i) + { + free(state.messages[i]); + } + + daFree(state.messages); + + return 0; +} diff --git a/term.c b/term.c new file mode 100644 index 0000000..e579e9e --- /dev/null +++ b/term.c @@ -0,0 +1,75 @@ +#include "term.h" +#include +#include + +Term createTerm() +{ + int x, y; + getmaxyx(stdscr, y, x); + + WINDOW * chatWin = newwin(y - 7, x - 48, 1, 1); + WINDOW * extraWin = newwin(y - 1, 46, 1, x - 47); + WINDOW * inputWin = newwin(6, x - 48, y - 6, 1); + + box(chatWin, 0, 0); + box(inputWin, 0, 0); + box(extraWin, 0, 0); + + wrefresh(chatWin); + wrefresh(inputWin); + wrefresh(extraWin); + + return (Term) { + .termX = x, + .termY = y, + .chat = chatWin, + .extra = extraWin, + .input = inputWin, + .inputY = getmaxy(inputWin) - 2, + .inputX = 1, + }; +} + +void recreateWindows(Term * term) +{ + int x, y; + getmaxyx(stdscr, y, x); + + term->termX = x; + term->termY = y; + + wborder(term->chat, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wborder(term->input, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + wborder(term->extra, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); + + wrefresh(term->chat); + wrefresh(term->input); + wrefresh(term->extra); + + delwin(term->chat); + delwin(term->input); + delwin(term->extra); + + term->chat = newwin(y - 7, x - 48, 1, 1); + term->extra = newwin(y - 1, 46, 1, x - 47); + term->input = newwin(6, x - 48, y - 6, 1); + + box(term->chat, 0, 0); + box(term->input, 0, 0); + box(term->extra, 0, 0); +} + +void initNcurses() +{ + initscr(); + raw(); + noecho(); + keypad(stdscr, TRUE); + refresh(); +} + +void deinitNcurses() +{ + endwin(); + system("reset"); +} diff --git a/term.h b/term.h new file mode 100644 index 0000000..c58e756 --- /dev/null +++ b/term.h @@ -0,0 +1,17 @@ +#ifndef TERM_H_ +#define TERM_H_ + +#include + +typedef struct Term { + int inputX, inputY; + WINDOW * chat, * input, * extra; + size_t termX, termY; +} Term; + +Term createTerm(); +void recreateWindows(Term * term); +void initNcurses(); +void deinitNcurses(); + +#endif // TERM_H_