mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@9949 387891d4-d844-0410-90c0-e4c51a9137d3
699 lines
14 KiB
C++
699 lines
14 KiB
C++
|
|
|
|
|
|
#ifdef SCP_UNIX
|
|
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <ctype.h>
|
|
#include <sys/time.h>
|
|
#include "SDL.h"
|
|
|
|
#if defined(APPLE_APP)
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_MALLOC_H)
|
|
#include <malloc.h>
|
|
#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];
|
|
|
|
#ifndef NDEBUG
|
|
#ifdef __APPLE__
|
|
#include <malloc/malloc.h>
|
|
#define MALLOC_USABLE(pointer) malloc_size(pointer)
|
|
#elif defined(SCP_SOLARIS)
|
|
#define MALLOC_USABLE(pointer) (*((size_t*)(pointer)-1))
|
|
#else
|
|
#ifdef SCP_BSD
|
|
#include <stdlib.h>
|
|
#include <malloc_np.h>
|
|
#endif
|
|
#define MALLOC_USABLE(pointer) malloc_usable_size(pointer)
|
|
#endif // __APPLE__
|
|
#endif // NDEBUG
|
|
|
|
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 ));
|
|
|
|
#ifdef Allow_NoWarn
|
|
if (Cmdline_nowarn) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// 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 ));
|
|
|
|
#ifdef Allow_NoWarn
|
|
if (Cmdline_nowarn) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// 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();
|
|
}
|
|
|
|
void WarningEx( char *filename, int line, const char *format, ... )
|
|
{
|
|
#ifndef NDEBUG
|
|
if (Cmdline_extra_warn) {
|
|
char msg[2 * MAX_BUF_SIZE];
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsprintf(msg, format, args);
|
|
va_end(args);
|
|
Warning(filename, line, msg);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// 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;
|
|
#ifndef APPLE_APP
|
|
int i;
|
|
int slen = 0;
|
|
#endif
|
|
|
|
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 replaced due to slow performance when freeing large amounts of memory
|
|
|
|
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
|
|
{
|
|
void *ptr = malloc( size );
|
|
|
|
if (!ptr) {
|
|
if (quiet) {
|
|
return NULL;
|
|
}
|
|
|
|
Error(LOCATION, "Out of memory.");
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
size_t used_size = MALLOC_USABLE(ptr);
|
|
if ( Watch_malloc ) {
|
|
// mprintf now uses SCP_strings = recursion! Whee!!
|
|
fprintf( stdout, "Malloc %zu bytes [%s(%d)]\n", used_size, clean_filename(filename), line );
|
|
}
|
|
|
|
TotalRam += used_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);
|
|
|
|
#ifndef NDEBUG
|
|
size_t old_size = MALLOC_USABLE(ptr);
|
|
#endif
|
|
|
|
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
|
|
size_t used_size = MALLOC_USABLE(ret_ptr);
|
|
if ( Watch_malloc ) {
|
|
// mprintf now uses SCP_strings = recursion! Whee!!
|
|
fprintf( stdout, "Realloc %zu bytes [%s(%d)]\n", used_size, clean_filename(filename), line );
|
|
}
|
|
|
|
TotalRam += (used_size - old_size);
|
|
#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
|
|
TotalRam -= MALLOC_USABLE(ptr);
|
|
#endif // !NDEBUG
|
|
|
|
free(ptr);
|
|
}
|
|
|
|
void vm_free_all()
|
|
{
|
|
}
|
|
|
|
#endif // SCP_UNIX
|