/* Win32-specific code for Xconq kernel. Copyright (C) 1999 Stanley T. Shebs. Xconq is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. See the file COPYING. */ /* Win32 interface stuff. Do NOT attempt to use this file in a non-Windows system! */ /* Also note that this file does not include all Xconq .h files, since it may be used with auxiliary programs. */ #include "config.h" #include "misc.h" #include "dir.h" #include "lisp.h" #include "module.h" #include "system.h" extern void close_displays(void); #include #include #include #include #include #include /* (should flush the following includes?) */ #include #include #include #include #include /* Default names for places. */ /* (should change default passed in by compiler instead) */ #undef XCONQDATA #ifndef XCONQDATA #define XCONQDATA ".." #endif #ifndef XCONQLIB #define XCONQLIB "lib" #endif #ifndef XCONQIMAGES #define XCONQIMAGES "images" #endif #ifndef XCONQSCORES #define XCONQSCORES "scores" #endif static char *game_homedir(void); static char *game_filename(char *namevar, char *defaultname); static char *score_file_pathname(char *name); uid_t games_uid; char * default_library_pathname(void) { char *name; name = xmalloc(strlen(XCONQDATA) + 1 + strlen(XCONQLIB) + 1); strcpy(name, XCONQDATA); strcat(name, "\\"); strcat(name, XCONQLIB); return name; } char * default_images_pathname(void) { char *name; name = xmalloc(strlen(XCONQDATA) + 1 + strlen(XCONQIMAGES) + 1); strcpy(name, XCONQDATA); strcat(name, "\\"); strcat(name, XCONQIMAGES); return name; } char * news_filename(void) { /* (should search in library list) */ make_pathname(xconq_libs->path, NEWSFILE, "", spbuf); return spbuf; } static char *savegamename; char * saved_game_filename(void) { if (savegamename == NULL) savegamename = game_filename("XCONQSAVEFILE", SAVEFILE); return savegamename; } char * checkpoint_filename(int n) { char *str, *home; home = game_homedir(); str = xmalloc(strlen(home) + 40); sprintf(str, "%s\\Check%d.Xconq", home, n); return str; } static char *preferences_name; char * preferences_filename(void) { if (preferences_name == NULL) preferences_name = game_filename("XCONQPREFERENCES", PREFERENCESFILE); return preferences_name; } char * error_save_filename(void) { /* No need to cache name, will only get requested once. */ return game_filename("XCONQERRORFILE", ERRORFILE); } char * statistics_filename(void) { /* No need to cache name, will only get requested once. */ return game_filename("XCONQSTATSFILE", STATSFILE); } static char *homedir; static char * game_homedir(void) { char *str; struct passwd *pwd; if (homedir != NULL) return homedir; if ((str = getenv("XCONQ_HOME")) != NULL) { homedir = copy_string(str); } else if ((str = getenv("HOME")) != NULL) { homedir = xmalloc(strlen(str) + 20); strcpy(homedir, str); strcat(homedir, "/_xconq"); } else if ((pwd = getpwuid(getuid())) != NULL) { homedir = xmalloc(strlen(pwd->pw_dir) + 20); strcpy(homedir, pwd->pw_dir); strcat(homedir, "/_xconq"); } else { homedir = "."; } /* Try to ensure that the directory exists. */ if (access(homedir, F_OK) != 0) { mkdir(homedir, 0755); /* (should warn of problems) */ } return homedir; } static char * game_filename(char *namevar, char *defaultname) { char *str, *home; if ((str = getenv(namevar)) != NULL && *str) return copy_string(str); home = game_homedir(); str = xmalloc(strlen(home) + 1 + strlen(defaultname) + 1); strcpy(str, home); strcat(str, "\\"); strcat(str, defaultname); return str; } /* This wrapper replaces fopen everywhere in the kernel. On the mac side it does unix-to-mac linefeed conversion if necessary. Here it does absolutely nothing. */ FILE * open_file(char *filename, char *mode) { return fopen(filename, mode); } /* Attempt to open a library file. */ FILE * open_module_library_file(Module *module) { LibraryPath *p; FILE *fp; /* Don't try to do on anon modules? */ if (module->name == NULL) return NULL; for_all_library_paths(p) { /* Generate library pathname. */ make_pathname(p->path, module->name, "g", spbuf); /* Now try to open the file. */ fp = open_file(spbuf, "r"); if (fp != NULL) { /* Remember the filename where we found it. */ module->filename = copy_string(spbuf); return fp; } } return NULL; } FILE * open_module_explicit_file(Module *module) { if (module->filename == NULL) return NULL; return (open_file(module->filename, "r")); } FILE * open_library_file(char *filename) { char fullnamebuf[1024]; LibraryPath *p; FILE *fp = NULL; fp = open_file(filename, "r"); if (fp != NULL) { return fp; } for_all_library_paths(p) { /* Generate library pathname. */ make_pathname(p->path, filename, NULL, fullnamebuf); fp = open_file(fullnamebuf, "r"); if (fp != NULL) { return fp; } } return NULL; } FILE * open_scorefile_for_reading(char *name) { char *fname; FILE *fp; fname = score_file_pathname(name); fp = open_file(fname, "r"); if (fp == NULL) { run_warning("Unable to open \"%s\" for reading; will retry once if you continue", fname); fp = open_file(fname, "r"); } return fp; } FILE * open_scorefile_for_writing(char *name) { char *fname; FILE *fp; fname = score_file_pathname(name); fp = open_file(fname, "a"); if (fp == NULL) { run_warning("Unable to open \"%s\" for writing; will retry once if you continue", fname); fp = open_file(fname, "a"); } return fp; } void close_scorefile_for_writing(FILE *fp) { fclose(fp); } static char *scorenamebuf; static char * score_file_pathname(char *name) { char *scorepath, extrabuf[BUFSIZE]; /* (Note that this wires in the name on the first call, so cannot be called with different names. We could make this smarter, but no point to it right now.) */ if (scorenamebuf == NULL) { scorepath = getenv("XCONQ_SCORES"); if (empty_string(scorepath)) { strcpy(extrabuf, XCONQDATA); strcat(extrabuf, "\\"); strcat(extrabuf, XCONQSCORES); scorepath = extrabuf; } scorenamebuf = xmalloc(strlen(scorepath) + 1 + strlen(name) + 10); make_pathname(scorepath, name, NULL, scorenamebuf); } return scorenamebuf; } void make_pathname(char *path, char *name, char *extn, char *pathbuf) { strcpy(pathbuf, ""); if (!empty_string(path)) { strcat(pathbuf, path); strcat(pathbuf, "/"); } strcat(pathbuf, name); /* Don't add a second identical extension, but do add if extension is different (in case we want "foo.12" -> "foo.12.g" for instance) */ if (strrchr(name, '.') && extn && strcmp((char *) strrchr(name, '.') + 1, extn) == 0) return; if (!empty_string(extn)) { strcat(pathbuf, "."); strcat(pathbuf, extn); } } /* Remove a given file. */ int remove_file(char *fname) { unlink(fname); /* (should return real outcome) */ return TRUE; } /* Default behavior on explicit kill. */ void stop_handler(int sig); void crash_handler(int sig); void hup_handler(int sig); void stop_handler(int sig) { close_displays(); exit(1); } /* This routine attempts to save the state before dying. */ void crash_handler(int sig) { static int already_been_here = FALSE; if (!already_been_here) { already_been_here = TRUE; close_displays(); printf("Fatal error encountered. Signal %d\n", sig); write_entire_game_state(error_save_filename()); } abort(); } /* Accidental disconnection saves state. */ void hup_handler(int sig) { static int already_been_here = FALSE; if (!already_been_here) { already_been_here = TRUE; close_displays(); printf("Somebody was disconnected, saving the game.\n"); write_entire_game_state(error_save_filename()); } abort(); } void init_signal_handlers(void) { signal(SIGINT, stop_handler); if (0 /* don't accidently quit */ && !Debug) { signal(SIGINT, SIG_IGN); } else { signal(SIGINT, SIG_DFL); /* signal(SIGINT, crash_handler); */ } signal(SIGHUP, hup_handler); signal(SIGSEGV, crash_handler); signal(SIGFPE, crash_handler); signal(SIGILL, crash_handler); signal(SIGINT, crash_handler); signal(SIGQUIT, crash_handler); signal(SIGTERM, crash_handler); /* The following signals may not be available everywhere. */ #ifdef SIGBUS signal(SIGBUS, crash_handler); #endif /* SIGBUS */ #ifdef SIGSYS signal(SIGSYS, crash_handler); #endif /* SIGSYS */ } struct timeval reallasttime = { 0, 0 }; struct timeval realcurtime; int n_seconds_elapsed(int n) { gettimeofday(&realcurtime, NULL); if (realcurtime.tv_sec > (reallasttime.tv_sec + (n - 1))) { reallasttime = realcurtime; return TRUE; } else { return FALSE; } } /* Returns true if n milliseconds have passed since the time was recorded via record_ms(). */ struct timeval reallastmstime = { 0, 0 }; int n_ms_elapsed(int n) { int interval; struct timeval tmprealtime; gettimeofday(&tmprealtime, NULL); interval = (tmprealtime.tv_sec - reallastmstime.tv_sec) * 1000 + (tmprealtime.tv_usec - reallastmstime.tv_usec) / 1000; return (interval > n); } /* Record the current time of day. */ void record_ms(void) { gettimeofday(&reallastmstime, NULL); }