[bedevtalk] Quake 3 SDL
Fredrik Modéen
fredrik.moden at telia.com
Wed Mar 1 04:21:53 BRT 2006
Hi
I found this
http://mitglied.lycos.de/Q3Coderz/quake3sdl/
http://www.idevgames.com/forum/showthread.php?t=10285
Can we do as they says but to Haiku/BeOS/Zeta?
I have looked on this at the most we need to changes this file (if we
don't can use the linux file)
as we have SDL 1.29 and SDL_net (don't know the version) and probably
some talks to Rudolf ;)
Can some one look at the file to se if we can use it stright of?
//Fredrik
-------------- next part --------------
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// qsdl_unix.c -- unix stuff that sdl can't handle yet
// Thx to BlackAura for the unix code :)
#include "../client/client.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <pwd.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
//=============================================================================
// Used to determine local installation path
static char installPath[MAX_OSPATH];
// Used to determine where to store user-specific files
static char homePath[MAX_OSPATH];
/*
========================================================================
MISC
========================================================================
*/
/*
==============
Sys_DefaultHomePath
==============
*/
void Sys_SetDefaultHomePath(const char *path)
{
Q_strncpyz(homePath, path, sizeof(homePath));
}
char *Sys_DefaultHomePath(void)
{
char *p;
if (*homePath)
return homePath;
if ((p = getenv("HOME")) != NULL)
{
Q_strncpyz(homePath, p, sizeof(homePath));
#ifdef MACOS_X
Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3");
#else
Q_strcat(homePath, sizeof(homePath), "/.q3a");
#endif
if (mkdir(homePath, 0777))
{
if (errno != EEXIST)
Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno);
}
return homePath;
}
return ""; // assume current dir
}
/*
==============
Sys_DefaultInstallPath
==============
*/
void Sys_SetDefaultInstallPath(const char *path)
{
Q_strncpyz(installPath, path, sizeof(installPath));
}
char *Sys_DefaultInstallPath(void)
{
if (*installPath)
return installPath;
else
return Sys_Cwd();
}
/*
==================
Sys_FixKeyboard
==================
*/
void Sys_FixKeyboard (void)
{
// Bandit: do we even need this on unix/mac ?
}
void Com_Memcpy (void* dest, const void* src, const size_t count) {
memcpy(dest, src, count);
}
void Com_Memset (void* dest, const int val, const size_t count) {
memset(dest, val, count);
}
void Snd_Memset (void* dest, const int val, const size_t count) {
memset(dest, val, count);
}
/*
==================
Sys_LowPhysicalMemory
==================
*/
#define MEM_THRESHOLD 96*1024*1024
qboolean Sys_LowPhysicalMemory(void)
{
#ifdef MACOS_X
return NSRealMemoryAvailable() <= MEM_THRESHOLD;
#else
// Bandit: any ideas how to get this working on linux ?
return qfalse;
#endif
}
/*
================
Sys_GetClipboardData
================
*/
char *Sys_GetClipboardData (void)
{
#ifdef MACOS_X
NSPasteboard *pasteboard;
NSArray *pasteboardTypes;
pasteboard = [NSPasteboard generalPasteboard];
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType])
{
NSString *clipboardString;
clipboardString = [pasteboard stringForType:NSStringPboardType];
if (clipboardString && [clipboardString length] > 0)
return strdup([clipboardString cString]);
}
return NULL;
#else
// Bandit: any ideas how to get this working on linux ?
return NULL;
#endif
}
/*
==============
Sys_Mkdir
==============
*/
void Sys_Mkdir (const char *path) { mkdir(path, 0777); }
/*
==============================================================
DIRECTORY SCANNING
==============================================================
*/
#define MAX_FOUND_FILES 0x1000
/*
================
Sys_ListFilteredFiles
================
*/
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
{
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
DIR *fdir;
struct dirent *d;
struct stat st;
if ( *numfiles >= MAX_FOUND_FILES - 1 )
return;
if (strlen(subdirs))
Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
else
Com_sprintf( search, sizeof(search), "%s", basedir );
if ((fdir = opendir(search)) == NULL)
return;
while ((d = readdir(fdir)) != NULL)
{
Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
if (stat(filename, &st) == -1)
continue;
if (st.st_mode & S_IFDIR)
{
if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, ".."))
{
if (strlen(subdirs))
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
else
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
}
if ( *numfiles >= MAX_FOUND_FILES - 1 )
break;
Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
if (!Com_FilterPath( filter, filename, qfalse ))
continue;
list[ *numfiles ] = CopyString( filename );
(*numfiles)++;
}
closedir(fdir);
}
/*
================
Sys_ListFiles
================
*/
char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
{
struct dirent *d;
// char *p; // bk001204 - unused
DIR *fdir;
qboolean dironly = wantsubs;
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
//int flag; // bk001204 - unused
int i;
struct stat st;
int extLen;
if (filter)
{
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
list[ nfiles ] = 0;
*numfiles = nfiles;
if (!nfiles)
return NULL;
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ )
listCopy[i] = list[i];
listCopy[i] = NULL;
return listCopy;
}
if ( !extension)
extension = "";
if ( extension[0] == '/' && extension[1] == 0 )
{
extension = "";
dironly = qtrue;
}
extLen = strlen( extension );
// search
nfiles = 0;
if ((fdir = opendir(directory)) == NULL)
{
*numfiles = 0;
return NULL;
}
while ((d = readdir(fdir)) != NULL)
{
Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
if (stat(search, &st) == -1)
continue;
if ((dironly && !(st.st_mode & S_IFDIR)) ||
(!dironly && (st.st_mode & S_IFDIR)))
continue;
if (*extension)
{
if ( strlen( d->d_name ) < strlen( extension ) ||
Q_stricmp(d->d_name + strlen( d->d_name ) - strlen( extension ), extension ) )
continue; // didn't match
}
if ( nfiles == MAX_FOUND_FILES - 1 )
break;
list[ nfiles ] = CopyString( d->d_name );
nfiles++;
}
list[ nfiles ] = 0;
closedir(fdir);
// return a copy of the list
*numfiles = nfiles;
if ( !nfiles )
return NULL;
listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
for ( i = 0 ; i < nfiles ; i++ )
listCopy[i] = list[i];
listCopy[i] = NULL;
return listCopy;
}
/*
================
Sys_FreeFileList
================
*/
void Sys_FreeFileList( char **list )
{
int i;
if ( !list )
return;
for ( i = 0 ; list[i] ; i++ )
Z_Free( list[i] );
Z_Free( list );
}
/*
========================================================================
UNIX CONSOLE
========================================================================
*/
qboolean stdin_active = qtrue;
// enable/disabled tty input mode
// NOTE TTimo this is used during startup, cannot be changed during run
static cvar_t *ttycon = NULL;
// general flag to tell about tty console mode
static qboolean ttycon_on = qfalse;
// when printing general stuff to stdout stderr (Sys_Printf)
// we need to disable the tty console stuff
// this increments so we can recursively disable
static int ttycon_hide = 0;
// some key codes that the terminal may be using
// TTimo NOTE: I'm not sure how relevant this is
static int tty_erase;
static int tty_eof;
static struct termios tty_tc;
static field_t tty_con;
// history
// NOTE TTimo this is a bit duplicate of the graphical console history
// but it's safer and faster to write our own here
#define TTY_HISTORY 32
static field_t ttyEditLines[TTY_HISTORY];
static int hist_current = -1, hist_count = 0;
// =============================================================
// tty console routines
// NOTE: if the user is editing a line when something gets printed to the early console then it won't look good
// so we provide tty_Clear and tty_Show to be called before and after a stdout or stderr output
// =============================================================
// flush stdin, I suspect some terminals are sending a LOT of shit
// FIXME TTimo relevant?
void tty_FlushIn()
{
char key;
while (read(0, &key, 1)!=-1);
}
// do a backspace
// TTimo NOTE: it seems on some terminals just sending '\b' is not enough
// so for now, in any case we send "\b \b" .. yeah well ..
// (there may be a way to find out if '\b' alone would work though)
void tty_Back()
{
char key;
key = '\b';
write(1, &key, 1);
key = ' ';
write(1, &key, 1);
key = '\b';
write(1, &key, 1);
}
// clear the display of the line currently edited
// bring cursor back to beginning of line
void tty_Hide()
{
int i;
assert(ttycon_on);
if (ttycon_hide)
{
ttycon_hide++;
return;
}
if (tty_con.cursor>0)
{
for (i=0; i<tty_con.cursor; i++)
{
tty_Back();
}
}
ttycon_hide++;
}
// show the current line
// FIXME TTimo need to position the cursor if needed??
void tty_Show()
{
int i;
assert(ttycon_on);
assert(ttycon_hide>0);
ttycon_hide--;
if (ttycon_hide == 0)
{
if (tty_con.cursor)
{
for (i=0; i<tty_con.cursor; i++)
{
write(1, tty_con.buffer+i, 1);
}
}
}
}
// never exit without calling this, or your terminal will be left in a pretty bad state
void Sys_ConsoleInputShutdown()
{
if (ttycon_on)
{
Com_Printf("Shutdown tty console\n");
tcsetattr (0, TCSADRAIN, &tty_tc);
}
}
void Hist_Add(field_t *field)
{
int i;
assert(hist_count <= TTY_HISTORY);
assert(hist_count >= 0);
assert(hist_current >= -1);
assert(hist_current <= hist_count);
// make some room
for (i=TTY_HISTORY-1; i>0; i--)
{
ttyEditLines[i] = ttyEditLines[i-1];
}
ttyEditLines[0] = *field;
if (hist_count<TTY_HISTORY)
{
hist_count++;
}
hist_current = -1; // re-init
}
field_t *Hist_Prev()
{
int hist_prev;
assert(hist_count <= TTY_HISTORY);
assert(hist_count >= 0);
assert(hist_current >= -1);
assert(hist_current <= hist_count);
hist_prev = hist_current + 1;
if (hist_prev >= hist_count)
{
return NULL;
}
hist_current++;
return &(ttyEditLines[hist_current]);
}
field_t *Hist_Next()
{
assert(hist_count <= TTY_HISTORY);
assert(hist_count >= 0);
assert(hist_current >= -1);
assert(hist_current <= hist_count);
if (hist_current >= 0)
{
hist_current--;
}
if (hist_current == -1)
{
return NULL;
}
return &(ttyEditLines[hist_current]);
}
// initialize the console input (tty mode if wanted and possible)
void Sys_ConsoleInputInit()
{
struct termios tc;
// TTimo
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=390
// ttycon 0 or 1, if the process is backgrounded (running non interactively)
// then SIGTTIN or SIGTOU is emitted, if not catched, turns into a SIGSTP
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
// FIXME TTimo initialize this in Sys_Init or something?
ttycon = Cvar_Get("ttycon", "1", 0);
if (ttycon && ttycon->value)
{
if (isatty(STDIN_FILENO)!=1)
{
Com_Printf("stdin is not a tty, tty console mode failed\n");
Cvar_Set("ttycon", "0");
ttycon_on = qfalse;
return;
}
Com_Printf("Started tty console (use +set ttycon 0 to disable)\n");
Field_Clear(&tty_con);
tcgetattr (0, &tty_tc);
tty_erase = tty_tc.c_cc[VERASE];
tty_eof = tty_tc.c_cc[VEOF];
tc = tty_tc;
/*
ECHO: don't echo input characters
ICANON: enable canonical mode. This enables the special
characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
STATUS, and WERASE, and buffers by lines.
ISIG: when any of the characters INTR, QUIT, SUSP, or
DSUSP are received, generate the corresponding sig
nal
*/
tc.c_lflag &= ~(ECHO | ICANON);
/*
ISTRIP strip off bit 8
INPCK enable input parity checking
*/
tc.c_iflag &= ~(ISTRIP | INPCK);
tc.c_cc[VMIN] = 1;
tc.c_cc[VTIME] = 0;
tcsetattr (0, TCSADRAIN, &tc);
ttycon_on = qtrue;
fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
} else
ttycon_on = qfalse;
}
/*
================
Sys_CreateConsole
================
*/
void Sys_CreateConsole (void)
{
}
/*
================
Sys_DestroyConsole
================
*/
void Sys_DestroyConsole (void)
{
Sys_ConsoleInputShutdown();
}
/*
================
Sys_ShowConsole
================
*/
void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
{
}
/*
================
Sys_ConsoleInput
================
*/
char *Sys_ConsoleInput (void)
{
// we use this when sending back commands
static char text[256];
int i;
int avail;
char key;
field_t *history;
if (ttycon && ttycon->value)
{
avail = read(0, &key, 1);
if (avail != -1)
{
// we have something
// backspace?
// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
if ((key == tty_erase) || (key == 127) || (key == 8))
{
if (tty_con.cursor > 0)
{
tty_con.cursor--;
tty_con.buffer[tty_con.cursor] = '\0';
tty_Back();
}
return NULL;
}
// check if this is a control char
if ((key) && (key) < ' ')
{
if (key == '\n')
{
// push it in history
Hist_Add(&tty_con);
strcpy(text, tty_con.buffer);
Field_Clear(&tty_con);
key = '\n';
write(1, &key, 1);
return text;
}
if (key == '\t')
{
tty_Hide();
Field_CompleteCommand( &tty_con );
// Field_CompleteCommand does weird things to the string, do a cleanup
// it adds a '\' at the beginning of the string
// cursor doesn't reflect actual length of the string that's sent back
tty_con.cursor = strlen(tty_con.buffer);
if (tty_con.cursor>0)
{
if (tty_con.buffer[0] == '\\')
{
for (i=0; i<=tty_con.cursor; i++)
{
tty_con.buffer[i] = tty_con.buffer[i+1];
}
tty_con.cursor--;
}
}
tty_Show();
return NULL;
}
avail = read(0, &key, 1);
if (avail != -1)
{
// VT 100 keys
if (key == '[' || key == 'O')
{
avail = read(0, &key, 1);
if (avail != -1)
{
switch (key)
{
case 'A':
history = Hist_Prev();
if (history)
{
tty_Hide();
tty_con = *history;
tty_Show();
}
tty_FlushIn();
return NULL;
break;
case 'B':
history = Hist_Next();
tty_Hide();
if (history)
{
tty_con = *history;
} else
{
Field_Clear(&tty_con);
}
tty_Show();
tty_FlushIn();
return NULL;
break;
case 'C':
return NULL;
case 'D':
return NULL;
}
}
}
}
Com_DPrintf("droping ISCTL sequence: %d, tty_erase: %d\n", key, tty_erase);
tty_FlushIn();
return NULL;
}
// push regular character
tty_con.buffer[tty_con.cursor] = key;
tty_con.cursor++;
// print the current line (this is differential)
write(1, &key, 1);
}
return NULL;
}
else
{
int len;
fd_set fdset;
struct timeval timeout;
if (!com_dedicated || !com_dedicated->value)
return NULL;
if (!stdin_active)
return NULL;
FD_ZERO(&fdset);
FD_SET(0, &fdset); // stdin
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
{
return NULL;
}
len = read (0, text, sizeof(text));
if (len == 0)
{ // eof!
stdin_active = qfalse;
return NULL;
}
if (len < 1)
return NULL;
text[len-1] = 0; // rip off the /n and terminate
return text;
}
}
/*
==============
Sys_Print
==============
*/
void Sys_Print (const char *msg)
{
if (ttycon_on)
{
tty_Hide();
}
fputs(msg, stderr);
if (ttycon_on)
{
tty_Show();
}
}
/*
================
Sys_SetErrorText
================
*/
void Sys_SetErrorText( const char *buf )
{
// Com_Printf("Error: %s\n", buf);
}
/*
========================================================================
SIGNAL HANDLING
========================================================================
*/
/*
================
SignalToString
================
*/
const char *SignalToString(int sig)
{
switch(sig)
{
case SIGHUP:
return "Hangup";
case SIGQUIT:
return "Terminal quit signal";
case SIGILL:
return "Illegal instruction";
case SIGTRAP:
return "Trace/breakpoint trap";
case SIGIOT:
return "Process abort signal";
case SIGBUS:
return "Access to an undefined portion of a memory object";
case SIGFPE:
return "Erroneous arithmetic operation";
case SIGSEGV:
return "Invalid memory reference";
case SIGTERM:
return "Termination signal";
default:
return "unknown";
}
}
/*
================
signal_handler
================
*/
static void signal_handler(int sig)
{
static qboolean signalcaught = qfalse;
if (signalcaught)
{
Com_Printf("DOUBLE SIGNAL FAULT: Received signal %d: \"%s\", exiting...\n", sig, SignalToString(sig));
exit(1);
}
signalcaught = qtrue;
Sys_Error("Received signal %d: \"%s\", exiting...\n", sig, SignalToString(sig));
}
/*
========================================================================
Platform-dependent startup and shutdown
========================================================================
*/
void Sys_PD_Init (void)
{
struct passwd *p;
// Add fatal signal handlers
signal(SIGHUP, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGILL, signal_handler);
signal(SIGTRAP, signal_handler);
signal(SIGIOT, signal_handler);
signal(SIGBUS, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGSEGV, signal_handler);
signal(SIGTERM, signal_handler);
// Username and architecture cvars
Cvar_Set( "arch", OSSTRING " " CPUSTRING);
if ( (p = getpwuid( getuid() )) == NULL )
Cvar_Set( "username", "player");
Cvar_Set("username", p->pw_name);
// TTY Console
Sys_ConsoleInputInit();
}
More information about the bedevtalk
mailing list