[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