//---------------------------------------------------------------------------- // EDGE Linux Misc System Code //---------------------------------------------------------------------------- // // Copyright (c) 1999-2005 The EDGE Team. // // This program 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 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //---------------------------------------------------------------------------- #include "i_defs.h" #include "i_sdlinc.h" #include "unx_sysinc.h" #include "version.h" #include "con_main.h" #include "dm_state.h" #include "e_main.h" #include "g_game.h" #include "m_argv.h" #include "m_misc.h" #include "m_random.h" #include "r_modes.h" #include "w_wad.h" #include "z_zone.h" #include #include #include #include #include #include #include #include #include #include #include #include "epi/timestamp.h" // FIXME: Use file_c handles extern FILE *logfile; extern FILE *debugfile; #ifdef USE_FLTK // remove some problematic #defines #undef VISIBLE #undef INVISIBLE #include #include #include #endif // USE_FLTK #ifndef USE_FLTK static char cp437_to_ascii[160] = { '.', '.', '.', '.', '.', '.', '.', '.', // 0x00 - 0x07 '.', '.', '.', '.', '.', '.', '.', '.', // 0x08 - 0x0F '>', '<', '.', '.', '.', '.', '.', '.', // 0x10 - 0x17 '.', '.', '.', '<', '.', '.', 'A', 'V', // 0x18 - 0x1F '.', '.', '.', '.', '.', '.', '.', '.', // 0x80 - 0x87 '.', '.', '.', '.', '.', '.', '.', '.', // 0x88 - 0x8F '.', '.', '.', '.', '.', '.', '.', '.', // 0x90 - 0x97 '.', '.', '.', '.', '.', '.', '.', '.', // 0x98 - 0x9F '.', '.', '.', '.', '.', '.', '.', '.', // 0xA0 - 0xA7 '.', '.', '.', '.', '.', '.', '.', '.', // 0xA8 - 0xAF '.', '%', '.', '|', '+', '+', '+', '.', // 0xB0 - 0xB7 '.', '+', '|', '+', '+', '.', '.', '+', // 0xB8 - 0xBF '+', '+', '+', '+', '-', '+', '+', '|', // 0xC0 - 0xC7 '+', '+', '+', '+', '+', '-', '+', '-', // 0xC8 - 0xCF '+', '-', '.', '.', '.', '.', '.', '+', // 0xD0 - 0xD7 '+', '+', '+', '.', '.', '.', '.', '.', // 0xD8 - 0xDF '.', '.', '.', '.', '.', '.', '.', '.', // 0xE0 - 0xE7 '.', '.', '.', '.', '.', '.', '.', '.', // 0xE8 - 0xEF '.', '.', '>', '<', '.', '.', '.', '.', // 0xF0 - 0xF7 '.', '.', '.', '.', '.', '.', '.', '.' // 0xF8 - 0xFF }; #endif // cleanup handling -- killough: static void I_SignalHandler(int s) { // CPhipps - report but don't crash on SIGPIPE if (s == SIGPIPE) { // -AJA- linux signals reset when raised. signal(SIGPIPE, I_SignalHandler); fprintf(stderr, "EDGE: Broken pipe\n"); return; } signal(s, SIG_IGN); // Ignore future instances of this signal. switch (s) { case SIGSEGV: I_Error("EDGE: Segmentation Violation"); break; case SIGINT: I_Error("EDGE: Interrupted by User"); break; case SIGILL: I_Error("EDGE: Illegal Instruction"); break; case SIGFPE: I_Error("EDGE: Floating Point Exception"); break; case SIGABRT: I_Error("EDGE: Aborted"); break; case SIGTERM: I_Error("EDGE: Killed"); break; } I_Error("EDGE: Terminated by signal %d", s); } void I_SetupSignalHandlers(bool allow_coredump) { signal(SIGPIPE, I_SignalHandler); // CPhipps - add SIGPIPE, as this is fatal if (allow_coredump) { // -AJA- Disable signal handlers, otherwise we don't get core dumps // and core dumps are _DAMN_ useful for debugging. return; } signal(SIGSEGV, I_SignalHandler); signal(SIGTERM, I_SignalHandler); signal(SIGILL, I_SignalHandler); signal(SIGFPE, I_SignalHandler); signal(SIGILL, I_SignalHandler); signal(SIGINT, I_SignalHandler); // killough 3/6/98: allow CTRL-BRK during init signal(SIGABRT, I_SignalHandler); } void I_CheckAlreadyRunning(void) { /* nothing needed */ } void I_ChangeToExeDir(const char *argv0) { const char *r = strrchr(argv0, '/'); if (r == NULL || r == argv0) return; #ifdef MACOSX // -AJA- It seems argv[0] points directly to the "gledge" binary // inside of the Edge.app folder (when run from the Finder). // Hence we need to strip the extra bits off. const char *app = r - 4; for (; app > argv0; app--) { if (app[0] == '.' && app[1] == 'a' && app[2] == 'p' && app[3] == 'p' && app[4] == '/') break; } if (app > argv0) { for (; app > argv0; app--) if (app[0] == '/') break; } if (app > argv0) r = app; #endif int length = (r - argv0) + 1; epi::string_c str; str.AddChars(argv0, 0, length); chdir(str.GetString()); } void I_WaitVBL (int count) { } // Most of the following has been rewritten by Lee Killough // and then by CPhipps // // I_GetTime // // CPhipps - believe it or not, it is possible with consecutive calls to // gettimeofday to receive times out of order, e.g you query the time twice and // the second time is earlier than the first. Cheap'n'cheerful fix here. // NOTE: only occurs with bad kernel drivers loaded, e.g. pc speaker drv unsigned long I_GetMicroSec (void) { struct timeval tv; struct timezone tz; gettimeofday (&tv, &tz); return (tv.tv_sec * 1000000 + tv.tv_usec); } static unsigned long lasttimereply; ///---int I_GetTime (void) ///---{ ///--- struct timeval tv; ///--- struct timezone tz; ///--- static unsigned long basetime = 0; ///--- unsigned long thistimereply; ///--- ///--- gettimeofday (&tv, &tz); ///--- ///--- // Fix for time problem ///--- thistimereply = (tv.tv_sec * TICRATE + (tv.tv_usec * TICRATE) / 1000000); ///--- ///--- if (!basetime) ///--- basetime = thistimereply; ///--- thistimereply -= basetime; ///--- ///--- if (thistimereply < lasttimereply) ///--- thistimereply = lasttimereply; ///--- ///--- return (lasttimereply = thistimereply); ///---} extern int autorun; // Autorun state bool microtimer_installed = 1; static char errmsg[4096]; // buffer of error message -- killough // killough 2/22/98: Add support for ENDBOOM, which is PC-specific // this converts BIOS color codes to ANSI codes. Its not pretty, but it // does the job - rain // CPhipps - made static static inline int convert_colour(int colour, int *bold) { *bold = 0; if (colour > 7) { colour &= 7; *bold = 1; } switch (colour) { case 1: return 4; case 3: return 6; case 4: return 1; case 6: return 3; } return colour; } // CPhipps - flags controlling ENDOOM behaviour enum { endoom_colours = 1, endoom_nonasciichars = 2, endoom_droplastline = 4 }; unsigned int endoom_mode; // // I_Warning // void I_Warning(const char *warning,...) { va_list argptr; va_start (argptr, warning); vsprintf (errmsg, warning, argptr); va_end (argptr); I_Printf ("WARNING: %s", errmsg); } // // I_Error // void I_Error(const char *error, ...) { va_list argptr; va_start (argptr, error); vsprintf (errmsg, error, argptr); va_end (argptr); if (logfile) { fprintf(logfile, "ERROR: %s\n", errmsg); fflush(logfile); } if (debugfile) { fprintf(debugfile, "ERROR: %s\n", errmsg); fflush(debugfile); } // -AJA- Commit suicide, thereby producing a core dump which may // come in handy for debugging the code that called I_Error(). if (M_CheckParm("-core")) { fprintf(stderr, "%s\n", errmsg); I_GrabCursor(false); raise(11); /* NOTREACHED */ } I_SystemShutdown(); I_MessageBox(errmsg, "EDGE Error"); I_CloseProgram(-1); } // -AJA- Routine which emulates IBM charset. #ifndef USE_FLTK static void PrintString(char *str) { for (; *str; str++) { int ch = (unsigned char) *str; if (ch == 0x7F || ch == '\r') continue; if ((0x20 <= ch && ch <= 0x7E) || ch == '\n' || ch == '\t') { putchar(ch); continue; } if (ch >= 0x80) ch -= 0x60; putchar(cp437_to_ascii[ch]); } fflush(stdout); } #endif void I_Printf(const char *message,...) { va_list argptr; char printbuf[2048]; char *string = printbuf; va_start(argptr, message); // Print the message into a text string vsprintf(printbuf, message, argptr); L_WriteLog("%s", printbuf); // If debuging enabled, print to the debugfile L_WriteDebug("%s", printbuf); // Clean up \n\r combinations while (*string) { if (*string == '\n') { memmove (string + 2, string + 1, strlen (string)); string[1] = '\r'; string++; } string++; } // Send the message to the console. CON_Printf("%s", printbuf); // And the text screen if in text mode #ifndef USE_FLTK PrintString(printbuf); #endif va_end(argptr); } void TextAttr (int attr) { // Not supported in Linux without low-level termios manipulation // or ncurses, which I'd rather not link // textattr(attr); } void ClearScreen (void) { I_Printf("\n"); } // // I_DisplayExitScreen // void I_DisplayExitScreen(void) { /* not implemented */ } // // I_CloseProgram // void I_CloseProgram(int exitnum) { exit(exitnum); } // // I_TraceBack // // Like I_CloseProgram, but may display some sort of debugging information // on some systems (typically the function call stack). void I_TraceBack(void) { I_CloseProgram(-1); } // // I_SystemStartup // // -ACB- 1998/07/11 Reformatted the code. // void I_SystemStartup(void) { Uint32 flags = 0; if (M_CheckParm("-core")) flags |= SDL_INIT_NOPARACHUTE; if (SDL_Init(flags) < 0) I_Error("Couldn't init SDL!!\n%s\n", SDL_GetError()); I_StartupNetwork(); I_StartupGraphics(); I_StartupControl(); I_StartupSound(); // -ACB- 1999/09/20 Sets nosound directly I_StartupMusic(); } // // I_SystemShutdown // // -ACB- 1998/07/11 Tidying the code // void I_SystemShutdown(void) { // makre sure audio is unlocked (e.g. I_Error occurred) I_UnlockAudio(); I_ShutdownMusic(); I_ShutdownSound(); I_ShutdownControl(); I_ShutdownGraphics(); I_ShutdownNetwork(); if (logfile) { fclose(logfile); logfile = NULL; } // -KM- 1999/01/31 Close the debugfile if (debugfile) { fclose(debugfile); debugfile = NULL; } } // // I_PureRandom // // Returns as-random-as-possible 32 bit values. // int I_PureRandom(void) { return ((int)time(NULL) ^ (int)I_ReadMicroSeconds()) & 0x7FFFFFFF; } // // I_ReadMicroSeconds // u32_t I_ReadMicroSeconds(void) { struct timeval tv; gettimeofday(&tv, NULL); return (u32_t)tv.tv_sec * 1000000 + (u32_t)tv.tv_usec; } // // I_Sleep // void I_Sleep(int millisecs) { //!!!! FIXME: use nanosleep ? usleep(millisecs * 1000); } // // I_GetModifiedTime // // -ACB- 2001/06/14 // bool I_GetModifiedTime(const char *filename, epi::timestamp_c *t) { struct stat buf; struct tm timeinf; // Check the sanity of the coders... if (!filename || !t) return false; // Check the file is invalid if (stat(filename, &buf)) return false; // Convert the 'time_t' of the modified time into something more human if(!localtime_r(&buf.st_mtime, &timeinf)) return false; t->Set(timeinf.tm_mday, timeinf.tm_mon+1, timeinf.tm_year+1900, timeinf.tm_hour, timeinf.tm_min, timeinf.tm_sec); return true; } // // I_MessageBox // void I_MessageBox(const char *message, const char *title) { #ifdef USE_FLTK Fl::scheme(NULL); fl_message_font(FL_HELVETICA /*_BOLD*/, 18); fl_message("%s", message); #else // USE_FLTK fprintf(stderr, "\n%s\n", message); #endif // USE_FLTK } //--- editor settings --- // vi:ts=4:sw=4:noexpandtab