#define TABULA_ENTRY_POINT 1
#include "client/client.h"
#include <GLFW/glfw3.h>
#include <uv.h>
#include <alias/str.h>
// vid
refexport_t re;
cvar_t *vid_gamma;
cvar_t *vid_fullscreen;
cvar_t *vid_ref;
viddef_t viddef; // global video state; used by other modules
void AppActivate(bool fActive, bool minimize) {
}
void VID_CheckChanges(void) {
}
void VID_Init(void) {
}
void VID_Shutdown(void) {
}
// net
void NET_Config(bool multiplayer) {
}
bool NET_StringToSockaddr(char *s, struct sockaddr *sadr) {
struct hostent *h;
char *colon;
char copy[128];
memset(sadr, 0, sizeof(*sadr));
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
((struct sockaddr_in *)sadr)->sin_port = 0;
strcpy(copy, s);
// strip off a trailing :port if present
for(colon = copy; *colon; colon++)
if(*colon == ':') {
*colon = 0;
((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon + 1));
}
if(copy[0] >= '0' && copy[0] <= '9') {
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
} else {
if(!(h = gethostbyname(copy)))
return 0;
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
}
return true;
}
static void SockadrToNetadr(struct sockaddr *s, netadr_t *a) {
if(s->sa_family == AF_INET) {
a->type = NA_IP;
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
a->port = ((struct sockaddr_in *)s)->sin_port;
// } else if(s->sa_family == AF_IPX) {
// a->type = NA_IPX;
// memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
// memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
// a->port = ((struct sockaddr_ipx *)s)->sa_socket;
}
}
bool NET_StringToAdr(char *s, netadr_t *a) {
struct sockaddr sadr;
if(!strcmp(s, "localhost")) {
memset(a, 0, sizeof(*a));
a->type = NA_LOOPBACK;
return true;
}
if(!NET_StringToSockaddr(s, &sadr))
return false;
SockadrToNetadr(&sadr, a);
return true;
}
bool NET_IsLocalAddress(netadr_t adr) { return adr.type == NA_LOOPBACK; }
char *NET_AdrToString(netadr_t a) {
static char s[64];
if(a.type == NA_LOOPBACK)
Com_sprintf(s, sizeof(s), "loopback");
else if(a.type == NA_IP)
Com_sprintf(s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
// else
// Com_sprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3],
// a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
return s;
}
bool NET_CompareAdr(netadr_t a, netadr_t b) {
if(a.type != b.type)
return false;
if(a.type == NA_LOOPBACK)
return true;
if(a.type == NA_IP) {
if(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
return true;
return false;
}
return false;
}
bool NET_CompareBaseAdr(netadr_t a, netadr_t b) {
if(a.type != b.type)
return false;
if(a.type == NA_LOOPBACK)
return true;
if(a.type == NA_IP) {
if(a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
return true;
return false;
}
return false;
}
void NET_Sleep(int msec) {
}
bool NET_GetPacket(netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message) {
return false;
}
void NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to) {
}
void NET_Init(void) {
}
// sys
unsigned int sys_frame_time;
unsigned int sys_msg_time;
int ActiveApp;
void Sys_Error(char *error, ...) {
va_list argptr;
CL_Shutdown();
Qcommon_Shutdown();
va_start(argptr, error);
vfprintf(stderr, error, argptr);
va_end(argptr);
exit(1);
}
static void windows_uv_idle_cb(uv_idle_t *handle) {
extern GLFWwindow *glfw_window;
if(glfw_window != NULL && glfwWindowShouldClose(glfw_window)) {
Com_Quit();
}
sys_msg_time = Sys_Milliseconds();
glfwPollEvents();
}
void Sys_Init(void) {
static uv_idle_t windows_uv_idle;
uv_idle_init(global_uv_loop(), &windows_uv_idle);
uv_idle_start(&windows_uv_idle, windows_uv_idle_cb);
}
void Sys_Quit(void) {
CL_Shutdown();
Qcommon_Shutdown();
exit(0);
}
char *Sys_ConsoleInput(void) {
return NULL;
}
void Sys_ConsoleOutput(char *string) {
}
char *Sys_GetClipboardData(void) {
return NULL;
}
void Sys_AppActivate(void) {
}
// --------------------------------------------------------------------------------------------------------------------
static struct {
char base[MAX_OSPATH];
char path[MAX_OSPATH + 2];
char pattern[MAX_OSPATH];
uv_dir_t *dir;
} find;
static int glob_match(const char *pattern, const char *text);
/* Like glob_match, but match PATTERN against any final segment of TEXT. */
static int glob_match_after_star(const char *pattern, const char *text) {
const char *p = pattern;
const char *t = text;
char c, c1;
while ((c = *p++) == '?' || c == '*')
if (c == '?' && *t++ == '\0')
return 0;
if (c == '\0')
return 1;
if (c == '\\')
c1 = *p;
else
c1 = c;
while (1) {
if ((c == '[' || *t == c1) && glob_match(p - 1, t))
return 1;
if (*t++ == '\0')
return 0;
}
}
/* Return nonzero if PATTERN has any special globbing chars in it. */
static int glob_pattern_p(const char *pattern)
{
const char *p = pattern;
char c;
int open = 0;
while ((c = *p++) != '\0')
switch (c) {
case '?':
case '*':
return 1;
case '[': /* Only accept an open brace if there is a close */
open++; /* brace to match it. Bracket expressions must be */
continue; /* complete, according to Posix.2 */
case ']':
if (open)
return 1;
continue;
case '\\':
if (*p++ == '\0')
return 0;
}
return 0;
}
static int glob_match(const char *pattern, const char *text) {
const char *p = pattern;
const char *t = text;
char c;
while ((c = *p++) != '\0')
switch (c) {
case '?':
if (*t == '\0')
return 0;
else
++t;
break;
case '\\':
if (*p++ != *t++)
return 0;
break;
case '*':
return glob_match_after_star(p, t);
case '[':
{
char c1 = *t++;
int invert;
if (!c1)
return (0);
invert = ((*p == '!') || (*p == '^'));
if (invert)
p++;
c = *p++;
while (1) {
register char cstart = c, cend = c;
if (c == '\\') {
cstart = *p++;
cend = cstart;
}
if (c == '\0')
return 0;
c = *p++;
if (c == '-' && *p != ']') {
cend = *p++;
if (cend == '\\')
cend = *p++;
if (cend == '\0')
return 0;
c = *p++;
}
if (c1 >= cstart && c1 <= cend)
goto match;
if (c == ']')
break;
}
if (!invert)
return 0;
break;
match:
/* Skip the rest of the [...] construct that already matched. */
while (c != ']') {
if (c == '\0')
return 0;
c = *p++;
if (c == '\0')
return 0;
else if (c == '\\')
++p;
}
if (invert)
return 0;
break;
}
default:
if (c != *t++)
return 0;
}
return *t == '\0';
}
static bool CompareAttributes(const char *path, const char *name, unsigned musthave, unsigned canthave) {
// . and .. never match
// if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
// return false;
alias_str fn;
alias_str_stack_format(fn, "%s/%s", path, name);
uv_fs_t req;
uv_fs_stat(global_uv_loop(), &req, fn, NULL);
uv_fs_req_cleanup(&req);
if(req.result < 0) {
return false; // shouldn't happen
}
if((req.statbuf.st_mode & S_IFDIR) && (canthave & SFF_SUBDIR)) {
return false;
}
if((musthave & SFF_SUBDIR) && !(req.statbuf.st_mode & S_IFDIR)) {
return false;
}
return true;
}
char *Sys_FindNext(unsigned musthave, unsigned canhave) {
if(find.dir == NULL)
return NULL;
uv_dirent_t dirent;
find.dir->nentries = 1;
find.dir->dirents = &dirent;
for(;;) {
uv_fs_t req;
int result = uv_fs_readdir(global_uv_loop(), &req, find.dir, NULL);
uv_fs_req_cleanup(&req);
if(result <= 0) {
Sys_FindClose();
return NULL;
}
if(!*find.pattern || glob_match(find.pattern, dirent.name)) {
//if(*findpattern) {
// printf("%s matched %sndpattern, d->d_name);
//}
if(CompareAttributes(find.base, dirent.name, musthave, canhave)) {
sprintf(find.path, "%s/%s", find.base, dirent.name);
return find.path;
}
}
}
}
char *Sys_FindFirst(const char *path, unsigned musthave, unsigned canhave) {
char *p;
if(find.dir != NULL) {
Sys_Error("Sys_BeginFind without close");
}
// COM_FilePath (path, findbase);
strcpy(find.base, path);
if((p = strrchr(find.base, '/')) != NULL) {
*p = 0;
strcpy(find.pattern, p + 1);
} else {
strcpy(find.pattern, "*");
}
if(strcmp(find.pattern, "*.*") == 0) {
strcpy(find.pattern, "*");
}
uv_fs_t req;
if(uv_fs_opendir(global_uv_loop(), &req, find.base, NULL) < 0) {
uv_fs_req_cleanup(&req);
return NULL;
}
find.dir = (uv_dir_t *)req.ptr;
uv_fs_req_cleanup(&req);
return Sys_FindNext(musthave, canhave);
}
void Sys_FindClose(void) {
if(find.dir != NULL) {
uv_fs_t req;
uv_fs_closedir(global_uv_loop(), &req, find.dir, NULL);
uv_fs_req_cleanup(&req);
}
find.dir = NULL;
}
// --------------------------------------------------------------------------------------------------------------------
void Sys_UnloadGame(void) {}