ref: a31cb3c76e7a74954b39dfa7155036e2e848e3ab
dir: /sys_unix.c/
#include "quakedef.h" #include "parg.h" #include <time.h> #include <errno.h> #include <fenv.h> #include <signal.h> #include <pthread.h> char *game; int debug; char lasterr[256] = {0}; static const char *disabled[32]; static int ndisabled; bool isdisabled(char *s) { int i; for(i = 0; i < ndisabled; i++){ if(strcmp(disabled[i], s) == 0) return true; } return false; } char * lerr(void) { static char lasterrcopy[256]; if(*lasterr == 0 && errno != 0) return strerror(errno); strcpy(lasterrcopy, lasterr); return lasterrcopy; } int sys_mkdir(char *path) { return (mkdir(path, 0770) == 0 || errno == EEXIST) ? 0 : -1; } char * sys_timestamp(void) { static char ts[32]; struct tm *tm; time_t t; if((t = time(nil)) == (time_t)-1 || (tm = localtime(&t)) == nil) return nil; snprint(ts, sizeof(ts), "%04d%02d%02d-%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); return ts; } int nrand(int n) { return random() % n; } void fatal(char *fmt, ...) { va_list arg; va_start(arg, fmt); vfprintf(stderr, fmt, arg); va_end(arg); Host_Shutdown(); exit(1); } void * emalloc(long n) { void *p; if(p = calloc(1, n), p == nil) fatal("emalloc"); setmalloctag(p, getcallerpc(&n)); return p; } uvlong nanosec(void) { static time_t sec0; struct timespec t; if(clock_gettime(CLOCK_MONOTONIC, &t) != 0) fatal("clock_gettime"); if(sec0 == 0) sec0 = t.tv_sec; t.tv_sec -= sec0; return t.tv_sec*1000000000ULL + t.tv_nsec; } double dtime(void) { return nanosec()/1000000000.0; } void game_shutdown(void) { stopfb(); Host_Shutdown(); exit(0); } static void * sighandler(void *ss) { int s; for(;;){ if(sigwait(ss, &s) != 0) break; } return nil; } int main(int argc, char **argv) { double t, t2, dt; struct parg_state ps; int c, nargs; static char *paths[] = { "/usr/games/quake", nil, nil, }; sigset_t ss; pthread_t tid; parg_init(&ps); nargs = 0; snailenabled = false; while((c = parg_getopt(&ps, argc, argv, "Ddg:N:S")) >= 0){ switch(c){ case 1: argv[nargs++] = (char*)ps.optarg; break; case 'N': if(ndisabled < nelem(disabled)) disabled[ndisabled++] = ps.optarg; break; case 'D': debug++; break; case 'd': dedicated = 1; break; case 'g': game = (char*)ps.optarg; break; case 'h': fprintf(stderr, "usage: qk1 [-g game]\n"); return 0; break; case 'S': snailenabled = true; break; case '?': fprintf(stderr, "unknown option -%c\n", ps.optopt); return 1; break; default: fprintf(stderr, "unhandled option -%c\n", c); return 1; break; } } sigemptyset(&ss); sigaddset(&ss, SIGPIPE); pthread_sigmask(SIG_BLOCK, &ss, NULL); pthread_create(&tid, nil, sighandler, &ss); if(snailenabled) initsnail(); srand(nanosec() + time(nil)); paths[1] = strdup(va("%s/.quake", getenv("HOME"))); Host_Init(nargs, argv, paths); fesetround(FE_TOWARDZERO); t = dtime() - 1.0 / Fpsmax; for(;;){ t2 = dtime(); dt = t2 - t; if(cls.state == ca_dedicated){ if(dt < sys_ticrate.value) continue; dt = sys_ticrate.value; } if(dt > sys_ticrate.value * 2) t = t2; else t += dt; Host_Frame(dt); } return 0; }