#ifdef SCP_UNIX #include #include #include #include #include #include #include #include "SDL.h" #if defined(APPLE_APP) #include #endif #if defined(HAVE_MALLOC_H) #include #endif #include "globalincs/pstypes.h" #include "parse/lua.h" #include "cmdline/cmdline.h" bool env_enabled = false; bool cell_enabled = false; int Global_warning_count = 0; int Global_error_count = 0; #define MAX_BUF_SIZE 1024 static char buffer[MAX_BUF_SIZE], buffer_tmp[MAX_BUF_SIZE]; char *strnset( char* string, int fill, size_t count) { char *p = string; for(; *p; p++ ) { if( count == 0 ) break; *p = (char)fill; count--; } return string; } // find the size of a file int filelength(int fd) { struct stat buf; if (fstat (fd, &buf) == -1) return -1; return buf.st_size; } // non-blocking process pause void Sleep(int mili) { #ifdef __APPLE__ // ewwww, I hate this!! SDL_Delay() is causing issues for us though and this // basically matches Apple examples of the same thing. Same as SDL_Delay() but // we aren't hitting up the system for anything during the process uint then = SDL_GetTicks() + mili; while (then > SDL_GetTicks()); #else SDL_Delay(mili); #endif } extern void os_deinit(); // fatal assertion error void WinAssert(char * text, char *filename, int line) { fprintf(stderr, "ASSERTION FAILED: \"%s\" at %s:%d\n", text, filename, line); // this stuff migt be really useful for solving bug reports and user errors. We should output it! mprintf(("ASSERTION: \"%s\" at %s:%d\n", text, strrchr(filename, '/')+1, line )); if (Cmdline_nowarn) { return; } // we have to call os_deinit() before abort() so we make sure that SDL gets // closed out and we don't lose video/input control os_deinit(); abort(); } // fatal assertion error void WinAssert(char * text, char *filename, int line, const char * format, ... ) { // Karajorma - Nicked the code from the Warning function below va_list args; int i; int slen = 0; memset( buffer, 0, sizeof(buffer) ); memset( buffer_tmp, 0, sizeof(buffer_tmp) ); va_start(args, format); vsnprintf(buffer_tmp, sizeof(buffer_tmp) - 1, format, args); va_end(args); slen = strlen(buffer_tmp); // strip out the newline char so the output looks better for (i = 0; i < slen; i++){ if (buffer_tmp[i] == (char)0x0a) { buffer[i] = ' '; } else { buffer[i] = buffer_tmp[i]; } } // kill off extra white space at end if (buffer[slen-1] == (char)0x20) { buffer[slen-1] = '\0'; } else { // just being careful buffer[slen] = '\0'; } fprintf(stderr, "ASSERTION FAILED: \"%s\" at %s:%d %s\n", text, filename, line, buffer); // this stuff migt be really useful for solving bug reports and user errors. We should output it! mprintf(("ASSERTION: \"%s\" at %s:%d %s\n", text, strrchr(filename, '/')+1, line, buffer )); if (Cmdline_nowarn) { return; } // we have to call os_deinit() before abort() so we make sure that SDL gets // closed out and we don't lose video/input control os_deinit(); abort(); } // standard warning message void Warning( char * filename, int line, const char * format, ... ) { Global_warning_count++; #ifndef NDEBUG va_list args; int i; int slen = 0; memset( buffer, 0, sizeof(buffer) ); memset( buffer_tmp, 0, sizeof(buffer_tmp) ); va_start(args, format); vsnprintf(buffer_tmp, sizeof(buffer_tmp) - 1, format, args); va_end(args); slen = strlen(buffer_tmp); // strip out the newline char so the output looks better for (i = 0; i < slen; i++){ if (buffer_tmp[i] == (char)0x0a) { buffer[i] = ' '; } else { buffer[i] = buffer_tmp[i]; } } // kill off extra white space at end if (buffer[slen-1] == (char)0x20) { buffer[slen-1] = '\0'; } else { // just being careful buffer[slen] = '\0'; } mprintf(("WARNING: \"%s\" at %s:%d\n", buffer, strrchr(filename, '/')+1, line)); // Order UP!! fprintf(stderr, "WARNING: \"%s\" at %s:%d\n", buffer, filename, line); #endif } // fatal error message void Error( const char * filename, int line, const char * format, ... ) { Global_error_count++; va_list args; int i; int slen = 0; memset( buffer, 0, sizeof(buffer) ); memset( buffer_tmp, 0, sizeof(buffer_tmp) ); va_start(args, format); vsnprintf(buffer_tmp, sizeof(buffer_tmp) - 1, format, args); va_end(args); mprintf(("ERROR: %s\nFile: %s\nLine: %d\n", buffer_tmp, filename, line)); #if defined(APPLE_APP) CFStringRef AsMessage; char AsText[1024]; CFOptionFlags result; snprintf(AsText, 1024, "Error: %s\n\nFile: %s\nLine %d\n", buffer_tmp, filename, line); AsMessage = CFStringCreateWithCString(NULL, AsText, kCFStringEncodingASCII); CFUserNotificationDisplayAlert(0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, CFSTR("Error!"), AsMessage, CFSTR("Exit"), NULL, NULL, &result); #else slen = strlen(buffer_tmp); // strip out the newline char so the output looks better for (i = 0; i < slen; i++){ if (buffer_tmp[i] == (char)0x0a) { buffer[i] = ' '; } else { buffer[i] = buffer_tmp[i]; } } // kill off extra white space at end if (buffer[slen-1] == (char)0x20) { buffer[slen-1] = '\0'; } else { // just being careful buffer[slen] = '\0'; } // Order UP!! fprintf(stderr, "ERROR: \"%s\" at %s:%d\n", buffer, filename, line); #endif exit(EXIT_FAILURE); } extern lua_Debug Ade_debug_info; void LuaError(struct lua_State *L, char *format, ...) { va_list args; memset( &buffer, 0, sizeof(buffer) ); if (format == NULL) { // make sure to cap to a sane string size snprintf( buffer, sizeof(buffer) - 1, "%s", lua_tostring(L, -1) ); lua_pop(L, -1); } else { va_start(args, format); vsnprintf(buffer, sizeof(buffer) - 1, format, args); va_end(args); } // Order UP!! fprintf(stderr, "LUA ERROR: \"%s\"\n", buffer); fprintf(stderr, "\n"); fprintf(stderr, "------------------------------------------------------------------\n"); fprintf(stderr, "ADE Debug:\n"); fprintf(stderr, "\n"); fprintf(stderr, "Name: %s\n", Ade_debug_info.name); fprintf(stderr, "Name of: %s\n", Ade_debug_info.namewhat); fprintf(stderr, "Function type: %s\n", Ade_debug_info.what); fprintf(stderr, "Defined on: %d\n", Ade_debug_info.linedefined); fprintf(stderr, "Upvalues: %d\n", Ade_debug_info.nups); fprintf(stderr, "\n" ); fprintf(stderr, "Source: %s\n", Ade_debug_info.source); fprintf(stderr, "Short source: %s\n", Ade_debug_info.short_src); fprintf(stderr, "Current line: %d\n", Ade_debug_info.currentline); fprintf(stderr, "------------------------------------------------------------------\n"); fprintf(stderr, "LUA Stack:\n"); fprintf(stderr, "\n"); ade_stackdump(L, buffer); fprintf(stderr, "%s\n", buffer); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } HMMIO mmioOpen(LPSTR szFilename, LPMMIOINFO lpmmioinfo, DWORD dwOpenFlags) { SDL_RWops *handle = NULL; char *mode = "rb"; if (dwOpenFlags & MMIO_READ) mode = "rb"; else if (dwOpenFlags & MMIO_READWRITE) mode = "r+b"; else if (dwOpenFlags & MMIO_WRITE) mode = "wb"; if ( szFilename != NULL ) { Assert( lpmmioinfo == NULL ); handle = SDL_RWFromFile( szFilename, mode ); } else if ( lpmmioinfo != NULL ) { Assert( szFilename == NULL ); handle = SDL_RWFromMem( lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer ); } return handle; } long mmioSeek(HMMIO hmmio, long lOffset, int iOrigin) { return (long) SDL_RWseek( hmmio, lOffset, iOrigin ); } long mmioRead(HMMIO hmmio, HPSTR pch, long cch) { return (long) SDL_RWread( hmmio, pch, 1, cch ); } MMRESULT mmioClose(HMMIO hmmio, uint wFlags) { if (wFlags != 0) STUB_FUNCTION; int rc = 0; rc = SDL_RWclose( hmmio ); if (rc) return MMIOERR_CANNOTWRITE; return 0; } // get a filename minus any leading path char *clean_filename(char *name) { char *p = name + strlen(name)-1; // Move p to point to first letter of EXE filename while( (p > name) && (*p != '\\') && (*p != '/') && (*p != ':') ) p--; p++; return p; } // high precision timer bool QueryPerformanceCounter(LARGE_INTEGER *pcount) { struct timeval timer_now; gettimeofday(&timer_now, NULL); pcount->QuadPart = (longlong)timer_now.tv_usec; return 1; } #ifndef NDEBUG int TotalRam = 0; #endif int Watch_malloc = 0; DCF_BOOL(watch_malloc, Watch_malloc ) #ifndef NDEBUG void windebug_memwatch_init() { //_CrtSetAllocHook(MyAllocHook); TotalRam = 0; } #endif // retrieve the current working directory int _getcwd(char *out_buf, unsigned int len) { if (getcwd(out_buf, len) == NULL) { Error(__FILE__, __LINE__, "buffer overflow in getcwd (buf size = %u)", len); } return 1; } // change directory to specified path int _chdir(const char *path) { int status = chdir(path); #ifndef NDEBUG int m_error = errno; if (status) { Warning(__FILE__, __LINE__, "Cannot chdir to %s: %s", path, strerror(m_error)); } #endif return status; } // make specified directory int _mkdir(const char *path) { int status = 1; // if we don't ever call mkdir() to update this then assume we are in error char *c, tmp_path[MAX_PATH]; memset(tmp_path, 0, MAX_PATH); strncpy(tmp_path, path, MAX_PATH-1); c = &tmp_path[1]; while (c++) { c = strchr(c, '/'); if (c) { *c = '\0'; status = mkdir(tmp_path, 0755); #ifndef NDEBUG int m_error = errno; if (status && (m_error != EEXIST) ) { Warning(__FILE__, __LINE__, "Cannot mkdir %s: %s", tmp_path, strerror(m_error)); } #endif *c = '/'; } } return status; } void _splitpath (char *path, char *drive, char *dir, char *fname, char *ext) { if ( (path == NULL) || (fname == NULL) ) return; // stop at these in case they ever get used, we need to support them at that point Assert( (dir == NULL) && (ext == NULL) ); /* fs2 only uses fname */ if (fname != NULL) { const char *ls = strrchr(path, '/'); if (ls != NULL) { ls++; // move past '/' } else { ls = path; } const char *lp = strrchr(path, '.'); if (lp == NULL) { lp = ls + strlen(ls); // move to the end } int dist = lp-ls; if (dist > (_MAX_FNAME-1)) dist = _MAX_FNAME-1; strncpy(fname, ls, dist); fname[dist] = 0; // add null, just in case } } // some type of info message int MessageBox(HWND h, const char *s1, const char *s2, int i) { if ( (h != NULL) && (i > -1) ) { // placeholder for some future time } fprintf(stderr, "%s: \"%s\"\n", s2, s1); return 0; } int MulDiv(int number, int numerator, int denominator) { int result; if (denominator == 0) return 0; longlong tmp; tmp = ((longlong) number) * ((longlong) numerator); tmp /= (longlong) denominator; result = (int) tmp; return result; } // lowercase a string void strlwr(char *s) { if (s == NULL) return; while (*s) { *s = tolower(*s); s++; } } /* ************************************* * * memory handling functions * * *************************************/ // RamTable stuff comes out of icculus.org #ifndef NDEBUG typedef struct RAM { ptr_u addr; int size; RAM *next; } RAM; static RAM *RamTable; #endif int vm_init(int min_heap_size) { #ifndef NDEBUG TotalRam = 0; #endif return 1; } #ifndef NDEBUG void *_vm_malloc( int size, char *filename, int line, int quiet ) #else void *_vm_malloc( int size, int quiet ) #endif { Assert( size > 0 ); void *ptr = malloc( size ); if (!ptr) { if (quiet) { return NULL; } Error(LOCATION, "Out of memory."); } #ifndef NDEBUG if ( Watch_malloc ) { mprintf(( "Malloc %d bytes [%s(%d)]\n", size, clean_filename(filename), line )); } RAM *next = (RAM *)malloc(sizeof(RAM)); next->addr = (ptr_u)ptr; next->size = (size + sizeof(RAM)); next->next = RamTable; RamTable = next; TotalRam += size; #endif return ptr; } #ifndef NDEBUG void *_vm_realloc( void *ptr, int size, char *filename, int line, int quiet ) #else void *_vm_realloc( void *ptr, int size, int quiet ) #endif { if (ptr == NULL) return vm_malloc(size); void *ret_ptr = realloc( ptr, size ); if (!ret_ptr) { if (quiet && (size > 0) && (ptr != NULL)) { // realloc doesn't touch the original ptr in the case of failure so we could still use it return NULL; } Error(LOCATION, "Out of memory."); } #ifndef NDEBUG RAM *item = RamTable; while (item != NULL) { if (item->addr == (ptr_u)ret_ptr) { TotalRam += (size - item->size); item->size = size; break; } item = item->next; } #endif return ret_ptr; } #ifndef NDEBUG char *_vm_strdup( const char *ptr, char *filename, int line ) #else char *_vm_strdup( const char *ptr ) #endif { char *dst; int len = strlen(ptr); dst = (char *)vm_malloc( len+1 ); if (!dst) return NULL; strcpy( dst, ptr ); return dst; } #ifndef NDEBUG char *_vm_strndup( const char *ptr, int size, char *filename, int line ) #else char *_vm_strndup( const char *ptr, int size ) #endif { char *dst; dst = (char *)vm_malloc( size+1 ); if (!dst) return NULL; strncpy( dst, ptr, size ); // make sure it has a NULL terminiator dst[size] = '\0'; return dst; } #ifndef NDEBUG void _vm_free( void *ptr, char *filename, int line ) #else void _vm_free( void *ptr ) #endif { if ( !ptr ) { #ifndef NDEBUG mprintf(("Why are you trying to free a NULL pointer? [%s(%d)]\n", clean_filename(filename), line)); #else mprintf(("Why are you trying to free a NULL pointer?\n")); #endif return; } #ifndef NDEBUG RAM *item = RamTable; RAM **mark = &RamTable; while (item != NULL) { if (item->addr == (ptr_u)ptr) { RAM *tmp = item; *mark = item->next; TotalRam -= tmp->size; free(tmp); break; } mark = &(item->next); item = item->next; } #endif // !NDEBUG free(ptr); } void vm_free_all() { } #endif // SCP_UNIX