Getting started
This commit is contained in:
commit
ce12bebb78
|
@ -0,0 +1,3 @@
|
|||
valgrind-out.txt
|
||||
Makefile
|
||||
main
|
|
@ -0,0 +1,156 @@
|
|||
#ifndef DA_H_
|
||||
#define DA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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
|
|
@ -0,0 +1,246 @@
|
|||
#include <curses.h>
|
||||
#include <errno.h>
|
||||
#include <ncurses.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <asm-generic/socket.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <bits/pthreadtypes.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
#include "term.h"
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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");
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef TERM_H_
|
||||
#define TERM_H_
|
||||
|
||||
#include <ncurses.h>
|
||||
|
||||
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_
|
Loading…
Reference in New Issue