From f294db4ccf45f6274e65260dd6f9a2c5faa94313 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 14 Aug 2007 20:18:08 +0000 Subject: Initial import of the new Q2PRO tree. --- source/sys_unix.c | 1143 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1143 insertions(+) create mode 100644 source/sys_unix.c (limited to 'source/sys_unix.c') diff --git a/source/sys_unix.c b/source/sys_unix.c new file mode 100644 index 0000000..8596ef7 --- /dev/null +++ b/source/sys_unix.c @@ -0,0 +1,1143 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program 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. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef __linux__ +#include +#endif + +#include "com_local.h" +#include "q_list.h" +#include "q_field.h" +#include "prompt.h" + +#ifdef DEDICATED_ONLY +#undef USE_SDL +#endif + +#ifdef USE_SDL +#include +#include +#endif + +cvar_t *sys_basedir; +cvar_t *sys_libdir; +cvar_t *sys_refdir; +cvar_t *sys_homedir; +cvar_t *sys_stdio; + +sysAPI_t sys; + +static qboolean tty_enabled; +static struct termios tty_orig; +static int tty_erase; +static commandPrompt_t tty_prompt; +static int tty_hidden; + +static byte sys_output_buffer[MAX_MSGLEN]; +static fifo_t sys_output = { + .data = sys_output_buffer, + .size = sizeof( sys_output_buffer ) +}; + +void Sys_Printf( const char *fmt, ... ); + +/* +=============================================================================== + +TERMINAL SUPPORT + +=============================================================================== +*/ + +static void Sys_HideInput( void ) { + int i; + + if( !tty_enabled ) { + return; + } + + if( !tty_hidden ) { + for( i = 0; i <= tty_prompt.inputLine.cursorPos; i++ ) { + FIFO_Write( &sys_output, "\b \b", 3 ); + } + } + tty_hidden++; +} + +static void Sys_ShowInput( void ) { + if( !tty_enabled ) { + return; + } + + if( !tty_hidden ) { + Com_EPrintf( "Sys_ShowInput: not hidden\n" ); + return; + } + + tty_hidden--; + if( !tty_hidden ) { + FIFO_Write( &sys_output, "]", 1 ); + FIFO_Write( &sys_output, tty_prompt.inputLine.text, + tty_prompt.inputLine.cursorPos ); + } +} + +static void Sys_InitTTY( void ) { + struct termios tty; + + tcgetattr( 0, &tty_orig ); + tty = tty_orig; + tty.c_lflag &= ~( ECHO | ICANON | INPCK | ISTRIP ); + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + tty_erase = tty.c_cc[VERASE]; + tcsetattr( 0, TCSADRAIN, &tty ); + tty_prompt.widthInChars = 80; + tty_prompt.Printf = Sys_Printf; + tty_enabled = qtrue; +} + +static void Sys_ShutdownTTY( void ) { + if( tty_enabled ) { + Sys_HideInput(); + Sys_RunConsole(); + tcsetattr( 0, TCSADRAIN, &tty_orig ); + } +} + +/* +================= +Sys_ConsoleOutput +================= +*/ +void Sys_ConsoleOutput( const char *string ) { + static char color_to_ansi[8] = { '0', '1', '2', '3', '4', '6', '5', '7' }; + char *data, *maxp, *p; + int length; + int color = 0; + + if( !tty_enabled ) { + data = p = FIFO_Reserve( &sys_output, &length ); + maxp = p + length; + while( *string ) { + if( Q_IsColorString( string ) ) { + string += 2; + continue; + } + *p++ = *string++ & 127; + if( p == maxp ) { + break; + } + } + + FIFO_Commit( &sys_output, p - data ); + return; + } + + Sys_HideInput(); + + data = p = FIFO_Reserve( &sys_output, &length ); + maxp = p + length; + while( *string ) { + if( Q_IsColorString( string ) ) { + color = string[1]; + string += 2; + if( p + 5 > maxp ) { + break; + } + p[0] = '\033'; + p[1] = '['; + if( color == COLOR_RESET ) { + p[2] = '0'; + p[3] = 'm'; + p += 4; + } else if( color == COLOR_ALT ) { + p[2] = '3'; + p[3] = '2'; + p[4] = 'm'; + p += 5; + } else { + p[2] = '3'; + p[3] = color_to_ansi[ ColorIndex( color ) ]; + p[4] = 'm'; + p += 5; + } + continue; + } + *p++ = *string++ & 127; + if( p == maxp ) { + break; + } + } + + if( color ) { + if( p + 4 > maxp ) { + p = maxp - 4; + } + p[0] = '\033'; + p[1] = '['; + p[2] = '0'; + p[3] = 'm'; + p += 4; + } + + FIFO_Commit( &sys_output, p - data ); + + Sys_ShowInput(); +} + +/* +================= +Sys_ParseInput +================= +*/ +static void Sys_ParseInput( const char *text ) { + inputField_t *f; + char *s; + int key; + + if( !tty_enabled ) { + Cbuf_AddText( text ); + return; + } + + f = &tty_prompt.inputLine; + while( *text ) { + key = *text++; + + if( key == tty_erase || key == 127 || key == 8 ) { + if( f->cursorPos ) { + f->text[--f->cursorPos] = 0; + FIFO_Write( &sys_output, "\b \b", 3 ); + } + continue; + } + + if( key >= 32 ) { + if( f->cursorPos < sizeof( f->text ) - 1 ) { + FIFO_Write( &sys_output, &key, 1 ); + f->text[f->cursorPos] = key; + f->text[++f->cursorPos] = 0; + } + continue; + } + + if( key == '\n' ) { + Sys_HideInput(); + s = Prompt_Action( &tty_prompt ); + if( s ) { + if( *s == '\\' || *s == '/' ) { + s++; + } + Sys_Printf( "]%s\n", s ); + Cbuf_AddText( s ); + } else { + FIFO_Write( &sys_output, "]\n", 2 ); + } + Sys_ShowInput(); + continue; + } + + if( key == '\t' ) { + Sys_HideInput(); + Prompt_CompleteCommand( &tty_prompt, qfalse ); + f->cursorPos = strlen( f->text ); + Sys_ShowInput(); + continue; + } + + //Com_Printf( "%s\n",Q_FormatString(text)); + if( *text ) { + key = *text++; + if( key == '[' || key == 'O' ) { + if( *text ) { + key = *text++; + if( key == 'A' ) { + Sys_HideInput(); + Prompt_HistoryUp( &tty_prompt ); + Sys_ShowInput(); + } else if( key == 'B' ) { + Sys_HideInput(); + Prompt_HistoryDown( &tty_prompt ); + Sys_ShowInput(); + } + } + } + } + } +} + +void Sys_RunConsole( void ) { + fd_set rfd, wfd; + struct timeval tv; + byte *data; + int length; + char text[MAX_STRING_CHARS]; + int ret; + + if( !sys_stdio->integer ) { + return; + } + + FD_ZERO( &rfd ); + FD_ZERO( &wfd ); + FD_SET( 0, &rfd ); // stdin + FD_SET( 1, &wfd ); // stdout + tv.tv_sec = 0; + tv.tv_usec = 0; + if( select( 2, &rfd, &wfd, NULL, &tv ) == -1 ) { + Com_Error( ERR_FATAL, "%s: select() failed", __func__ ); + } + + if( FD_ISSET( 0, &rfd ) ) { + ret = read( 0, text, sizeof( text ) ); + if( !ret ) { + Com_DPrintf( "Read EOF from stdin.\n" ); + Sys_ShutdownTTY(); + Cvar_Set( "sys_stdio", "0" ); + return; + } + if( ret < 0 ) { + Com_Error( ERR_FATAL, "%s: %d bytes read", __func__, ret ); + } + text[ret] = 0; + + Sys_ParseInput( text ); + } + + if( FD_ISSET( 1, &wfd ) ) { + data = FIFO_Peek( &sys_output, &length ); + if( length ) { + ret = write( 1, data, length ); + if( ret <= 0 ) { + Com_Error( ERR_FATAL, "%s: %d bytes written", __func__, ret ); + } + FIFO_Decommit( &sys_output, ret ); + } + } +} + +/* +=============================================================================== + +HUNK + +=============================================================================== +*/ + +void Hunk_Begin( mempool_t *pool, int maxsize ) { + byte *buf; + + // reserve a huge chunk of memory, but don't commit any yet + pool->maxsize = ( maxsize + 4095 ) & ~4095; + pool->cursize = 0; + buf = mmap( NULL, pool->maxsize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANON, -1, 0 ); + if( buf == NULL || buf == ( byte * )-1 ) { + Com_Error( ERR_FATAL, "Hunk_Begin: unable to virtual allocate %d bytes", + pool->maxsize ); + } + pool->base = buf; + pool->mapped = pool->maxsize; +} + +void *Hunk_Alloc( mempool_t *pool, int size ) { + byte *buf; + + // round to cacheline + size = ( size + 31 ) & ~31; + if( pool->cursize + size > pool->maxsize ) { + Com_Error( ERR_FATAL, + "Hunk_Alloc: unable to allocate %d bytes out of %d", + size, pool->maxsize ); + } + buf = pool->base + pool->cursize; + pool->cursize += size; + return buf; +} + +void Hunk_End( mempool_t *pool ) { + byte *n; + +#ifndef __linux__ + size_t old_size = pool->maxsize; + size_t new_size = pool->cursize; + void * unmap_base; + size_t unmap_len; + + new_size = round_page(new_size); + old_size = round_page(old_size); + if (new_size > old_size) { + Com_Error( ERR_FATAL, "Hunk_End: new_size > old_size" ); + } + if (new_size < old_size) { + unmap_base = (caddr_t)(pool->base + new_size); + unmap_len = old_size - new_size; + n = munmap(unmap_base, unmap_len) + pool->base; + } +#else + n = mremap( pool->base, pool->maxsize, pool->cursize, 0 ); +#endif + if( n != pool->base ) { + Com_Error( ERR_FATAL, "Hunk_End: could not remap virtual block: %s", + strerror( errno ) ); + } + pool->mapped = pool->cursize; +} + +void Hunk_Free( mempool_t *pool ) { + if( pool->base ) { + if( munmap( pool->base, pool->mapped ) ) { + Com_Error( ERR_FATAL, "Hunk_Free: munmap failed: %s", + strerror( errno ) ); + } + } + memset( pool, 0, sizeof( *pool ) ); +} + + +/* +=============================================================================== + +GENERAL ROUTINES + +=============================================================================== +*/ + +void Sys_DebugBreak( void ) { + raise( SIGTERM ); +} + +/* +================ +Sys_Milliseconds +================ +*/ +int curtime; + +int Sys_Milliseconds( void ) { + struct timeval tp; + static int secbase; + + gettimeofday( &tp, NULL ); + + if( !secbase ) { + secbase = tp.tv_sec; + return tp.tv_usec / 1000; + } + + curtime = ( tp.tv_sec - secbase ) * 1000 + tp.tv_usec / 1000; + + return curtime; +} + +uint32 Sys_Realtime( void ) { + struct timeval tp; + uint32 time; + + gettimeofday( &tp, NULL ); + time = tp.tv_sec * 1000 + tp.tv_usec / 1000; + return time; +} + +/* +================ +Sys_Mkdir +================ +*/ +void Sys_Mkdir( const char *path ) { + mkdir( path, 0777 ); +} + +qboolean Sys_RemoveFile( const char *path ) { + if( remove( path ) ) { + return qfalse; + } + return qtrue; +} + +qboolean Sys_RenameFile( const char *from, const char *to ) { + if( rename( from, to ) ) { + return qfalse; + } + return qtrue; +} + +/* +================ +Sys_GetFileInfo +================ +*/ +qboolean Sys_GetFileInfo( const char *path, fsFileInfo_t *info ) { + struct stat st; + qtime_t *ctime, *mtime; + + if( stat( path, &st ) ) { + return qfalse; + } + + info->fileSize = st.st_size; + ctime = localtime( &st.st_ctime ); + mtime = localtime( &st.st_mtime ); + info->timeCreate = *ctime; + info->timeModify = *mtime; + + return qtrue; +} + +/* +================= +Sys_Quit +================= +*/ +void Sys_Quit( void ) { + Sys_ShutdownTTY(); + exit( 0 ); +} + +/* +================= +Sys_GetClipboardData +================= +*/ +char *Sys_GetClipboardData( void ) { +#ifdef USE_SDL + SDL_SysWMinfo info; + Display *dpy; + Window sowner, win; + Atom type, property; + unsigned long len, bytes_left; + unsigned char *data; + int format, result; + char *ret; + + if( SDL_WasInit( SDL_INIT_VIDEO ) != SDL_INIT_VIDEO ) { + return NULL; + } + SDL_VERSION( &info.version ); + if( !SDL_GetWMInfo( &info ) ) { + return NULL; + } + if( info.subsystem != SDL_SYSWM_X11 ) { + return NULL; + } + + dpy = info.info.x11.display; + win = info.info.x11.window; + + sowner = XGetSelectionOwner( dpy, XA_PRIMARY ); + if( sowner == None ) { + return NULL; + } + + property = XInternAtom( dpy, "GETCLIPBOARDDATA_PROP", False ); + + XConvertSelection( dpy, XA_PRIMARY, XA_STRING, property, win, CurrentTime ); + + XSync( dpy, False ); + + result = XGetWindowProperty( dpy, win, property, 0, 0, False, + AnyPropertyType, &type, &format, &len, &bytes_left, &data ); + + if( result != Success ) { + return NULL; + } + + ret = NULL; + if( bytes_left ) { + result = XGetWindowProperty( dpy, win, property, 0, bytes_left, True, + AnyPropertyType, &type, &format, &len, &bytes_left, &data ); + if( result == Success ) { + ret = Z_CopyString( ( char * )data ); + } + } + + XFree( data ); + + return ret; +#else + return NULL; +#endif +} + +/* +================= +Sys_SetClipboardData +================= +*/ +void Sys_SetClipboardData( const char *data ) { +} + +/* +================= +Sys_GetCurrentDirectory +================= +*/ +char *Sys_GetCurrentDirectory( void ) { + static char curpath[MAX_OSPATH]; + + getcwd( curpath, sizeof( curpath ) ); + + return curpath; +} + +void Sys_AddDefaultConfig( void ) { + FILE *fp; + struct stat st; + char *text; + + if( stat( DEFCFG, &st ) == -1 ) { + return; + } + + fp = fopen( DEFCFG, "r" ); + if( !fp ) { + return; + } + + Com_Printf( "Execing " DEFCFG "\n" ); + text = Cbuf_Alloc( &cmd_buffer, st.st_size ); + if( text ) { + fread( text, st.st_size, 1, fp ); + } + + fclose( fp ); +} + +/* +================ +Sys_FillAPI +================ +*/ +void Sys_FillAPI( sysAPI_t *api ) { + api->Milliseconds = Sys_Milliseconds; + api->GetClipboardData = Sys_GetClipboardData; + api->SetClipboardData = Sys_SetClipboardData; + api->HunkBegin = Hunk_Begin; + api->HunkAlloc = Hunk_Alloc; + api->HunkEnd = Hunk_End; + api->HunkFree = Hunk_Free; +} + +/* +================= +Sys_Kill +================= +*/ +static void Sys_Kill( int signum ) { + signal( SIGTERM, SIG_DFL ); + signal( SIGINT, SIG_DFL ); + signal( SIGSEGV, SIG_DFL ); + + Com_Printf( "Received signal %d, exiting\n", signum ); + Com_Quit(); +} + +/* +================= +Sys_Segv +================= +*/ +static void Sys_Segv( int signum ) { + signal( SIGTERM, SIG_DFL ); + signal( SIGINT, SIG_DFL ); + signal( SIGSEGV, SIG_DFL ); + + Sys_ShutdownTTY(); + +#ifdef USE_SDL + SDL_ShowCursor( SDL_ENABLE ); + SDL_WM_GrabInput( SDL_GRAB_OFF ); + SDL_Quit(); +#endif + + fprintf( stderr, "Received signal SIGSEGV, segmentation fault\n" ); + + exit( 1 ); +} + +/* +================= +Sys_Init +================= +*/ +void Sys_Init( void ) { + char homedir[MAX_OSPATH]; + char *s; + + signal( SIGTERM, Sys_Kill ); + signal( SIGINT, Sys_Kill ); + signal( SIGSEGV, Sys_Segv ); + signal( SIGTTIN, SIG_IGN ); + signal( SIGTTOU, SIG_IGN ); + + // basedir + // allows the game to run from outside the data tree + sys_basedir = Cvar_Get( "basedir", DATADIR, CVAR_NOSET ); + + // homedir + // specifies per-user writable directory for demos, screenshots, etc + s = getenv( "HOME" ); + if( s && *s ) { + Com_sprintf( homedir, sizeof( homedir ), "%s/"HOMEDIR, s ); + } else { + homedir[0] = 0; + } + sys_homedir = Cvar_Get( "homedir", homedir, CVAR_NOSET ); + + sys_libdir = Cvar_Get( "libdir", LIBDIR, CVAR_NOSET ); + sys_refdir = Cvar_Get( "refdir", REFDIR, CVAR_NOSET ); + + sys_stdio = Cvar_Get( "sys_stdio", "2", CVAR_NOSET ); + + if( sys_stdio->integer ) { + // change stdin and stdout to non-blocking + fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | FNDELAY ); + fcntl( 1, F_SETFL, fcntl( 1, F_GETFL, 0 ) | FNDELAY ); + + // init TTY support + if( sys_stdio->integer > 1 ) { + if( isatty( 0 ) == 1 ) { + Sys_InitTTY(); + } else { + Com_DPrintf( "stdin in not a tty, tty input disabled.\n" ); + Cvar_SetInteger( "sys_stdio", 1 ); + } + } + } + + Sys_FillAPI( &sys ); +} + +/* +================ +Sys_Printf +================ +*/ +void Sys_Printf( const char *fmt, ... ) { + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + Sys_ConsoleOutput( msg ); +} + +/* +================= +Sys_Error +================= +*/ +void Sys_Error( const char *error, ... ) { + va_list argptr; + char text[MAXPRINTMSG]; + + Sys_ShutdownTTY(); + +#ifdef USE_SDL + SDL_ShowCursor( SDL_ENABLE ); + SDL_WM_GrabInput( SDL_GRAB_OFF ); + SDL_Quit(); +#endif + + va_start( argptr, error ); + Q_vsnprintf( text, sizeof( text ), error, argptr ); + va_end( argptr ); + + fprintf( stderr, "********************\n" + "FATAL: %s\n" + "********************\n", text ); + exit( 1 ); +} + + +/*void floating_point_exception_handler( int whatever ) { + signal( SIGFPE, floating_point_exception_handler ); +}*/ + + +/* +======================================================================== + +DLL LOADING + +======================================================================== +*/ + +/* +================= +Sys_FreeLibrary +================= +*/ +void Sys_FreeLibrary( void *handle ) { + if( !handle ) { + return; + } + if( dlclose( handle ) ) { + Com_Error( ERR_FATAL, "dlclose failed on %p", handle ); + } +} + +/* +================= +Sys_LoadLibrary +================= +*/ +void *Sys_LoadLibrary( const char *path, const char *sym, void **handle ) { + void *module, *entry; + + *handle = NULL; + + module = dlopen( path, RTLD_NOW ); + if( !module ) { + Com_DPrintf( "%s failed: %s\n", __func__, dlerror() ); + return NULL; + } + + entry = dlsym( module, sym ); + if( !entry ) { + Com_DPrintf( "%s failed: %s\n", __func__, dlerror() ); + dlclose( module ); + return NULL; + } + + Com_DPrintf( "%s succeeded: %s\n", __func__, path ); + + *handle = module; + + return entry; +} + +void *Sys_GetProcAddress( void *handle, const char *sym ) { + return dlsym( handle, sym ); +} + +/* +=============================================================================== + +MISC + +=============================================================================== +*/ + +static inline void st2fi( struct stat *st, fsFileInfo_t *info ) { + qtime_t *ctime = localtime( &st->st_ctime ); + qtime_t *mtime = localtime( &st->st_mtime ); + + info->fileSize = st->st_size; + info->timeCreate = *ctime; + info->timeModify = *mtime; +} + + +/* +================= +Sys_ListFilteredFiles +================= +*/ +static void Sys_ListFilteredFiles( char **listedFiles, int *count, + const char *path, const char *filter, uint flags, int length, int depth ) +{ + struct dirent *findInfo; + DIR *findHandle; + struct stat st; + char findPath[MAX_OSPATH]; + fsFileInfo_t info; + char *name; + + if( depth >= 32 ) { + return; + } + + if( *count >= MAX_LISTED_FILES ) { + return; + } + + if( ( findHandle = opendir( path ) ) == NULL ) { + return; + } + + while( ( findInfo = readdir( findHandle ) ) != NULL ) { + if( !strcmp( findInfo->d_name, "." ) ) { + continue; + } + if( !strcmp( findInfo->d_name, ".." ) ) { + continue; + } + Com_sprintf( findPath, sizeof( findPath ), "%s/%s", + path, findInfo->d_name ); + + if( stat( findPath, &st ) == -1 ) { + continue; + } + + if( st.st_mode & S_IFDIR ) { + Sys_ListFilteredFiles( listedFiles, count, findPath, + filter, flags, length, depth + 1 ); + } + + if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { + if( !( st.st_mode & S_IFDIR ) ) { + continue; + } + } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { + if( st.st_mode & S_IFDIR ) { + continue; + } + } + + if( !FS_WildCmp( filter, findPath + length ) ) { + continue; + } + if( flags & FS_SEARCH_SAVEPATH ) { + name = findPath + length; + } else { + name = findInfo->d_name; + } + + if( flags & FS_SEARCH_EXTRAINFO ) { + st2fi( &st, &info ); + listedFiles[( *count )++] = FS_CopyExtraInfo( name, &info ); + } else { + listedFiles[( *count )++] = Z_CopyString( name ); + } + if( *count >= MAX_LISTED_FILES ) { + break; + } + + } + + closedir( findHandle ); +} + + +/* +================= +Sys_ListFiles +================= +*/ +char **Sys_ListFiles( const char *path, const char *extension, + uint32 flags, int *numFiles ) +{ + struct dirent *findInfo; + DIR *findHandle; + struct stat st; + char findPath[MAX_OSPATH]; + char *listedFiles[MAX_LISTED_FILES]; + fsFileInfo_t info; + int count; + char **list; + char *s; + int i, length; + + count = 0; + + if( numFiles ) { + *numFiles = 0; + } + + if( flags & FS_SEARCH_BYFILTER ) { + length = strlen( path ); + if( !length ) { + return NULL; + } + Sys_ListFilteredFiles( listedFiles, &count, path, + extension, flags, length + 1, 0 ); + } else { + if( ( findHandle = opendir( path ) ) == NULL ) { + return NULL; + } + + while( ( findInfo = readdir( findHandle ) ) != NULL ) { + if( !strcmp( findInfo->d_name, "." ) ) { + continue; + } + if( !strcmp( findInfo->d_name, ".." ) ) { + continue; + } + + Com_sprintf( findPath, sizeof( findPath ), "%s/%s", + path, findInfo->d_name ); + + if( stat( findPath, &st ) == -1 ) { + continue; + } + if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_ONLY ) { + if( !( st.st_mode & S_IFDIR ) ) { + continue; + } + } else if( ( flags & FS_SEARCHDIRS_MASK ) == FS_SEARCHDIRS_NO ) { + if( st.st_mode & S_IFDIR ) { + continue; + } + } + + if( extension ) { + s = COM_FileExtension( findInfo->d_name ); + if( !FS_ExtCmp( extension, s ) ) { + continue; + } + } + + if( flags & FS_SEARCH_SAVEPATH ) { + s = findPath; + } else { + s = findInfo->d_name; + } + if( flags & FS_SEARCH_EXTRAINFO ) { + st2fi( &st, &info ); + listedFiles[count++] = FS_CopyExtraInfo( s, &info ); + } else { + listedFiles[count++] = Z_CopyString( s ); + } + + if( count >= MAX_LISTED_FILES ) { + break; + } + } + + closedir( findHandle ); + } + + if( !count ) { + return NULL; + } + + qsort( listedFiles, count, sizeof( listedFiles[0] ), SortStrcmp ); + + list = Z_Malloc( sizeof( char * ) * ( count + 1 ) ); + for( i = 0; i < count; i++ ) { + list[i] = listedFiles[i]; + } + list[count] = NULL; + + if( numFiles ) { + *numFiles = count; + } + + return list; +} + +/* +================= +Sys_FreeFileList +================= +*/ +void Sys_FreeFileList( char **list ) { + char **p; + + if( !list ) { + Com_Error( ERR_FATAL, "Sys_FreeFileList: NULL" ); + } + + p = list; + while( *p ) { + Z_Free( *p++ ); + } + + Z_Free( list ); +} + +/* +=============================================================================== + +MAIN + +=============================================================================== +*/ + +static void _Qcommon_Init_ArgcArgv( int argc, char **argv ) { + int i, length; + char *cmdline; + + if( argc < 2 ) { + Qcommon_Init( NULL ); + return; + } + + length = 0; + for( i = 1; i < argc; i++ ) { + length += strlen( argv[i] ) + 1; + } + + cmdline = alloca( length ); + if( cmdline != NULL ) { + cmdline[0] = 0; + for( i = 1; i < argc - 1; i++ ) { + strcat( cmdline, argv[i] ); + strcat( cmdline, " " ); + } + strcat( cmdline, argv[i] ); + } + + Qcommon_Init( cmdline ); +} + +/* +================= +main +================= +*/ +int main( int argc, char **argv ) { + int i; + + for( i = 1; i < argc; i++ ) { + if( !strcmp( argv[1], "-v" ) || !strcmp( argv[1], "--version" ) ) { + printf( APPLICATION " " VERSION " " __DATE__ " " BUILDSTRING " " + CPUSTRING "\n" ); + return 0; + } + } + + if ( !getuid() || !geteuid() ) { + Sys_Error( "You cannot run " APPLICATION " as superuser " + "for security reasons" ); + } + + _Qcommon_Init_ArgcArgv( argc, argv ); + while( 1 ) { + Qcommon_Frame(); + } + +} + -- cgit v1.2.3