From 6b260962eef4caa486ceee9a60b61c67269025c6 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Wed, 18 Jan 2017 22:16:55 +0100 Subject: Initial --- .gitignore | 3 ++ Makefile | 26 ++++++++++ global.c | 16 +++++++ global.h | 10 ++++ main.c | 90 +++++++++++++++++++++++++++++++++++ memory.c | 11 +++++ memory.h | 16 +++++++ showmenu.c | 53 +++++++++++++++++++++ showmenu.h | 5 ++ tcp.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tcp.h | 31 ++++++++++++ 11 files changed, 418 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 global.c create mode 100644 global.h create mode 100644 main.c create mode 100644 memory.c create mode 100644 memory.h create mode 100644 showmenu.c create mode 100644 showmenu.h create mode 100644 tcp.c create mode 100644 tcp.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a62f14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.dSYM +regexbattle diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..563919e --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +CC = gcc +CFLAGS = -Wall -Wextra -Wwrite-strings -Wconversion -Wno-sign-conversion \ + -std=c11 -g -fwrapv -I$(TERMIO_PREFIX)/include +LDFLAGS = -L$(TERMIO_PREFIX)/lib -ltermio + +TERMIO_PREFIX = $(HOME)/prefix + +BIN = regexbattle + +obj_files = $(patsubst %.c,%.o,$(wildcard *.c)) + +.PHONY: all clean remake + +all: $(BIN) + +clean: + rm -rf $(BIN) *.o *.dSYM + +remake: clean + make all + +$(BIN): $(obj_files) + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c *.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/global.c b/global.c new file mode 100644 index 0000000..27f522c --- /dev/null +++ b/global.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include +#include +#include +#include "global.h" + +__attribute__((noreturn, format (printf, 1, 2))) +void throw(const char *format,...){ + char *buf; + va_list ap; + va_start(ap,format); + vasprintf(&buf,format,ap); + va_end(ap); + fprintf(stderr,"THROW: %s\n",buf); + exit(1); +} diff --git a/global.h b/global.h new file mode 100644 index 0000000..61d8cee --- /dev/null +++ b/global.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +typedef int64_t i64; +typedef uint64_t u64; + + +void throw(const char *format,...) __attribute__((noreturn, format (printf, 1, 2))); diff --git a/main.c b/main.c new file mode 100644 index 0000000..1dcdc1f --- /dev/null +++ b/main.c @@ -0,0 +1,90 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include "memory.h" +#include "showmenu.h" +#include "tcp.h" + +#define HOSTNAME "localhost" +#define PORT 1423 + +#define GAMENAME "regexbattle" + + +static char *die_message=NULL; + +__attribute__((noreturn, format (printf,1,2))) +static void die(const char *format,...){ + va_list ap; + va_start(ap,format); + char *buf; + int ret=vasprintf(&buf,format,ap); + va_end(ap); + if(ret<0){ + die_message=strdup("Double error roll"); + } else { + die_message=buf; + } + exit(1); +} + +static void exit_cleanup(void){ + endkeyboard(); + endscreen(); + if(die_message!=NULL){ + printf("%s\n",die_message); + } +} + +int main(void){ + int sock=tcp_connect(HOSTNAME,PORT); + if(sock==-1){ + printf("Could not connect to %s:%d\n",HOSTNAME,PORT); + return 1; + } + char *recvbuf=NULL; + i64 recvbufsz=0; + tcp_send_line(sock,"ping"); + tcp_read_line(sock,&recvbuf,&recvbufsz); + if(strcmp(recvbuf,"pong")!=0){ + printf("Protocol error; different server running on %s:%d?\n",HOSTNAME,PORT); + return 1; + } + + initscreen(); + initkeyboard(false); + installCLhandler(true); + atexit(exit_cleanup); + + clearscreen(); + + while(true){ + i64 sel=showmenu("REGEXBATTLE", + "List public rooms","Create a room","Join a room", + "Quit",NULL); + switch(sel){ + case 0:{ + tcp_send_line(sock,"room_list " GAMENAME); + TcpList *list=tcp_read_list(sock,"room_list"); + if(list==NULL)die("Protocol error: receiving list"); + Size termsize=gettermsize(); + fillrect(0,7,termsize.w,termsize.h-7,' '); + moveto(0,7); + for(i64 i=0;initems&&i+7items[i]); + } + break; + } + + case 1: break; + case 2: break; + case 3: return 0; + } + } +} diff --git a/memory.c b/memory.c new file mode 100644 index 0000000..6f8253f --- /dev/null +++ b/memory.c @@ -0,0 +1,11 @@ +#include +#include "memory.h" + + +void* check_after_allocation(const char *funcname, void *ptr){ + if(ptr == NULL){ + perror(funcname); + exit(1); + } + return ptr; +} diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..6fcb7e1 --- /dev/null +++ b/memory.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + + +#define malloc(num, type) \ + ((type*)check_after_allocation("malloc", malloc((num)*sizeof(type)))) +#define calloc(num, type) \ + ((type*)check_after_allocation("calloc", calloc((num), sizeof(type)))) +#define realloc(ptr, num, type) \ + ((type*)check_after_allocation("realloc", realloc(ptr, (num)*sizeof(type)))) +#define strdup(str) \ + ((char*)check_after_allocation("strdup", strdup(str))) + +void* check_after_allocation(const char *funcname, void *ptr); diff --git a/showmenu.c b/showmenu.c new file mode 100644 index 0000000..2e1bfbd --- /dev/null +++ b/showmenu.c @@ -0,0 +1,53 @@ +#include +#include +#include "memory.h" +#include "showmenu.h" + +static int menu_index; + +static void menu_callback(int index){ + menu_index=index; +} + +i64 showmenu(const char *title,...){ + va_list ap,ap2; + va_start(ap,title); + va_copy(ap2,ap); + i64 nargs=0; + while(va_arg(ap2,const char*)!=NULL)nargs++; + va_end(ap2); + + moveto(2,0); + tprintf("=== %s ===",title); + + Menudata menudata; + menudata.nitems=(int)nargs; + menudata.items=malloc(nargs,Menuitem); + for(i64 i=0;i +#include +#include +#include +#include +#include +#include +#include "global.h" +#include "memory.h" +#include "tcp.h" + +i64 tcp_read_line(int sock,char **buf,i64 *bufsz){ + if(*bufsz==0||*buf==NULL){ + *bufsz=512; + *buf=malloc(*bufsz,char); + } + i64 len=0; + while(true){ + if(len==*bufsz-1){ + *bufsz*=2; + *buf=realloc(*buf,*bufsz,char); + } + i64 ret=recv(sock,*buf+len,1,0); + if(ret<=0)return -1; + if((*buf)[len]=='\n'){ + (*buf)[len]='\0'; + return len; + } + len++; + } +} + +i64 sock_read_data(int sock,char *buf,i64 length){ + i64 got=0; + while(gotnitems=nitems; + list->items=malloc(nitems,char*); + walker=argstart; + for(i64 i=0;iitems[i]=strdup(strsep(&walker," ")); + } + + return list; +} + + +static const char* itoa(int n){ + static char buf[64]; + sprintf(buf,"%d",n); + return buf; +} + + +int tcp_connect(const char *hostname,int port){ + struct addrinfo hints,*res; + memset(&hints,0,sizeof(hints)); + hints.ai_family=AF_UNSPEC; + hints.ai_socktype=SOCK_STREAM; + int ret=getaddrinfo(hostname,itoa(port),&hints,&res); + if(ret!=0){ + return -1; + } + + int sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol); + if(sock==-1)return -1; + if(connect(sock,res->ai_addr,res->ai_addrlen)==-1)return -1; + return sock; +} diff --git a/tcp.h b/tcp.h new file mode 100644 index 0000000..a09732a --- /dev/null +++ b/tcp.h @@ -0,0 +1,31 @@ +#pragma once + +#include "global.h" + +//Unless specified otherwise, functions return -1 on error or socket closure. + +//If *bufsz==0 || *buf==NULL, allocates buf newly. +//Returns line length; reallocates buf if needed. +i64 tcp_read_line(int sock,char **buf,i64 *bufsz); + +i64 tcp_read_data(int sock,char *buf,i64 length); + +i64 tcp_send_data(int sock,const char *buf,i64 length); +i64 tcp_send_str(int sock,const char *str); +i64 tcp_send_line(int sock,const char *str); +i64 tcp_send_line_f(int sock,const char *format,...) __attribute__((format (printf,2,3))); + + +i64 tcp_read_ok(int sock,const char *tag); + +typedef struct TcpList{ + i64 nitems; + char **items; +} TcpList; + +//Returns NULL on error instead of -1. +TcpList* tcp_read_list(int sock,const char *tag); + + +//Returns the socket. +int tcp_connect(const char *hostname,int port); -- cgit v1.2.3