Files
fs2open.github.com/code/windows_stub/stubs.cpp
T
taylor ba590e029d get rid of non-standard itoa(), make use of the proper sprintf() instead
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@4086 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 18:42:56 +10:00

730 lines
16 KiB
C++

/*
* $Logfile: $
* $Revision: 2.35 $
* $Date: 2007-03-22 22:14:57 $
* $Author: taylor $
*
* OS-dependent functions.
*
* $Log: not supported by cvs2svn $
* Revision 2.34 2007/01/07 12:39:59 taylor
* build for for newer GCC versions
*
* Revision 2.33 2006/09/08 06:20:15 taylor
* fix things that strict compiling balked at (from compiling with -ansi and -pedantic)
*
* Revision 2.32 2006/05/27 16:39:40 taylor
* remove non-Windows timeSetEvent() functions
* make PDWORD and LPDWORD int instead of long (64-bit issue) (thanks Spike)
* fix 64-bit ptr issue with OpenAL audio streaming code (thanks Spike)
* add start of device enumberation for OpenAL 1.1 (it just lists available devices now)
* make sure we open the default OpenAL 1.1 device under Windows
* comment out blank listener stuff, this may have been crashing under OS X
* add support for AL_BYTE_OFFSET in OpenAL 1.1 for buffer positioning under Windows
*
* Revision 2.31 2006/04/16 05:24:16 taylor
* probably doesn't need to be world readable, but certainly doesn't need to be world writeable
* add Assert() to can when we are stupidly trying to allocate 0 or less size bytes in vm_malloc()
*
* Revision 2.30 2006/03/15 17:32:13 taylor
* bump error msg buffer size a little (I'll probably just go dynamic with this since you hopefully won't get this too much anyway)
*
* Revision 2.29 2006/03/08 05:22:14 taylor
* remove asm from MulDiv() since Intel Mac doesn't like it very much, and it doesn't do exactly what it should anyway
*
* Revision 2.28 2006/01/31 15:44:55 taylor
* remove USE_LUA
*
* Revision 2.27 2006/01/21 00:11:51 taylor
* fix for LuaError change, *again* ;)
*
* Revision 2.26 2006/01/13 14:19:34 taylor
* move SDL autoconf checks up so we get the defines earlier
* fix some Lua build problems on Linux (enabled by default now, but with configure option)
* newline fixage
* comment fixage
*
* Revision 2.25 2005/10/27 16:23:03 taylor
* go back to using abort() over exit() for Assert's and Int3's but close out SDL first this time, makes debugging much easier
*
* Revision 2.24 2005/10/17 05:48:18 taylor
* dynamically allocate object collision pairs
*
* Revision 2.23 2005/10/11 08:30:38 taylor
* fix memory freakage from dynamic spawn weapon types
*
* Revision 2.22 2005/09/22 11:21:22 taylor
* delay for fox OS X, SDL messes up for some reason and though I don't like this, even Apple does it
*
* Revision 2.21 2005/09/14 20:38:12 taylor
* some vm_* fixage for Windows
*
* Revision 2.20 2005/09/06 05:32:12 taylor
* use exit(EXIT_FAILURE) rather than abort() so that all atexit() calls will actually get executed
*
* Revision 2.19 2005/09/05 09:38:19 taylor
* merge of OSX tree
* a lot of byte swaps were still missing, will hopefully be fully network compatible now
*
* Revision 2.18 2005/08/14 21:01:59 Kazan
* I'm stupid, sorry - fixed release-build-crash
*
* Revision 2.17 2005/06/22 15:18:58 taylor
* make sure that _mkdir() will return an error if the path is invalid
*
* Revision 2.16 2005/05/28 19:44:17 taylor
* haven't got a clue what I was thinking with that crap
*
* Revision 2.15 2005/05/24 20:52:10 taylor
* make sure that we recursively create directories for Linux/OSX
* replace older recursive mkdir method in cfileextractor with new method
*
* Revision 2.14 2005/05/12 17:49:18 taylor
* use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros
* fixes various problems and is past time to make the switch
*
* Revision 2.13 2005/04/21 15:52:24 taylor
* stupid little comment fix, no big deal
*
* Revision 2.12 2005/04/11 05:45:38 taylor
* _endthread() doesn't take an argument so do support one (Jens Granseuer)
* debug variable fixes in freespace.cpp (Jens Granseuer)
* as a safety catch we should Assert() on future usage of things we don't yet support in *nix _splitpath()
*
* Revision 2.11 2005/03/27 08:51:25 taylor
* this is what coding on an empty stomach will get you
*
* Revision 2.10 2005/03/27 06:17:54 taylor
* fill in some stuff for timer and mmio calls, not 100% but it works ok
*
* Revision 2.9 2005/03/24 23:22:59 taylor
* make sure we will get the right error message
*
* Revision 2.8 2005/03/10 08:00:18 taylor
* change min/max to MIN/MAX to fix GCC problems
* add lab stuff to Makefile
* build unbreakage for everything that's not MSVC++ 6
* lots of warning fixes
* fix OpenGL rendering problem with ship insignias
* no Warnings() in non-debug mode for Linux (like Windows)
* some campaign savefile fixage to stop reverting everyones data
*
* Revision 2.7 2005/02/04 10:12:33 taylor
* merge with Linux/OSX tree - p0204
*
* Revision 2.6 2005/01/30 18:32:42 taylor
* merge with Linux/OSX tree - p0130
* remove extra brace in cfile.cpp
*
*
* $NoKeywords: $
*/
#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"
bool env_enabled = false;
bool cell_enabled = false;
#define MAX_BUF_SIZE 240
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);
// 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, char * format, ... )
{
#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';
}
// Order UP!!
fprintf(stderr, "WARNING: \"%s\" at %s:%d\n", buffer, filename, line);
#endif
}
// fatal error message
void Error( char * filename, int line, char * format, ... )
{
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);
#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);
}
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);
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 *buffer, unsigned int len)
{
if (getcwd(buffer, 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