2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00:00
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 .
*/
2014-09-22 08:55:46 +00:00
2010-02-15 23:26:55 +00:00
// common.c -- misc functions used in client and server
# include "quakedef.h"
2013-09-25 17:01:40 +00:00
# include "q_ctype.h"
2010-12-30 16:50:15 +00:00
# include <errno.h>
2020-07-19 00:36:32 +00:00
# include <sys/stat.h>
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
# ifndef _WIN32
2018-05-01 00:35:14 +00:00
# include <dirent.h>
# include <fnmatch.h>
# ifndef FNM_CASEFOLD
# define FNM_CASEFOLD 0 //not available. I guess we're not on gnu/linux
# endif
2017-09-17 02:12:53 +00:00
# endif
2011-12-28 23:40:27 +00:00
static char * largv [ MAX_NUM_ARGVS + 1 ] ;
static char argvdummy [ ] = " " ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
int safemode ;
2010-02-15 23:26:55 +00:00
2012-04-20 19:47:22 +00:00
cvar_t registered = { " registered " , " 1 " , CVAR_ROM } ; /* set to correct value in COM_CheckRegistered() */
2011-12-28 23:40:27 +00:00
cvar_t cmdline = { " cmdline " , " " , CVAR_ROM /*|CVAR_SERVERINFO*/ } ; /* sending cmdline upon CCREQ_RULE_INFO is evil */
2017-09-17 02:12:53 +00:00
cvar_t allow_download = { " allow_download " , " 1 " } ; /*set to 0 to block file downloads, both client+server*/
2010-02-15 23:26:55 +00:00
2014-09-08 21:10:33 +00:00
static qboolean com_modified ; // set true if using non-id files
2010-02-15 23:26:55 +00:00
2010-02-18 11:45:18 +00:00
qboolean fitzmode ;
2011-12-29 15:10:18 +00:00
static void COM_Path_f ( void ) ;
2010-02-15 23:26:55 +00:00
// if a packfile directory differs from this, it is assumed to be hacked
2012-03-28 17:50:47 +00:00
# define PAK0_COUNT 339 /* id1/pak0.pak - v1.0x */
# define PAK0_CRC_V100 13900 /* id1/pak0.pak - v1.00 */
# define PAK0_CRC_V101 62751 /* id1/pak0.pak - v1.01 */
# define PAK0_CRC_V106 32981 /* id1/pak0.pak - v1.06 */
# define PAK0_CRC (PAK0_CRC_V106)
# define PAK0_COUNT_V091 308 /* id1/pak0.pak - v0.91/0.92, not supported */
# define PAK0_CRC_V091 28804 /* id1/pak0.pak - v0.91/0.92, not supported */
2010-02-15 23:26:55 +00:00
char com_token [ 1024 ] ;
int com_argc ;
char * * com_argv ;
2011-12-28 23:40:27 +00:00
# define CMDLINE_LENGTH 256 /* johnfitz -- mirrored in cmd.c */
2010-02-15 23:26:55 +00:00
char com_cmdline [ CMDLINE_LENGTH ] ;
qboolean standard_quake = true , rogue , hipnotic ;
// this graphic needs to be in the pak file to use registered features
2011-12-28 23:40:27 +00:00
static unsigned short pop [ ] =
{
0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 ,
0x0000 , 0x0000 , 0x6600 , 0x0000 , 0x0000 , 0x0000 , 0x6600 , 0x0000 ,
0x0000 , 0x0066 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0067 , 0x0000 ,
0x0000 , 0x6665 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0065 , 0x6600 ,
0x0063 , 0x6561 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0061 , 0x6563 ,
0x0064 , 0x6561 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0061 , 0x6564 ,
0x0064 , 0x6564 , 0x0000 , 0x6469 , 0x6969 , 0x6400 , 0x0064 , 0x6564 ,
0x0063 , 0x6568 , 0x6200 , 0x0064 , 0x6864 , 0x0000 , 0x6268 , 0x6563 ,
0x0000 , 0x6567 , 0x6963 , 0x0064 , 0x6764 , 0x0063 , 0x6967 , 0x6500 ,
0x0000 , 0x6266 , 0x6769 , 0x6a68 , 0x6768 , 0x6a69 , 0x6766 , 0x6200 ,
0x0000 , 0x0062 , 0x6566 , 0x6666 , 0x6666 , 0x6666 , 0x6562 , 0x0000 ,
0x0000 , 0x0000 , 0x0062 , 0x6364 , 0x6664 , 0x6362 , 0x0000 , 0x0000 ,
0x0000 , 0x0000 , 0x0000 , 0x0062 , 0x6662 , 0x0000 , 0x0000 , 0x0000 ,
0x0000 , 0x0000 , 0x0000 , 0x0061 , 0x6661 , 0x0000 , 0x0000 , 0x0000 ,
0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x6500 , 0x0000 , 0x0000 , 0x0000 ,
0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x6400 , 0x0000 , 0x0000 , 0x0000
2010-02-15 23:26:55 +00:00
} ;
/*
All of Quake ' s data access is through a hierchal file system , but the contents
of the file system can be transparently merged from several sources .
The " base directory " is the path to the directory holding the quake . exe and all
game directories . The sys_ * files pass this to host_init in quakeparms_t - > basedir .
This can be overridden with the " -basedir " command line parm to allow code
debugging in a different directory . The base directory is only used during
filesystem initialization .
The " game directory " is the first tree on the search path and directory that all
generated files ( savegames , screenshots , demos , config files ) will be saved to .
This can be overridden with the " -game " command line parameter . The game
directory can never be changed while quake is executing . This is a precacution
against having a malicious server instruct clients to write files over areas they
shouldn ' t .
The " cache directory " is only used during development to save network bandwidth ,
especially over ISDN / T1 lines . If there is a cache directory specified , when
a file is found by the normal search path , it will be mirrored into the cache
directory , then opened there .
FIXME :
The file " parms.txt " will be read out of the game directory and appended to the
current command line arguments to allow different games to initialize startup
parms differently . This could be used to add a " -sspeed 22050 " for the high
quality sound edition . Because they are added at the end , they will not
override an explicit setting on the original command line .
*/
//============================================================================
// ClearLink is used for new headnodes
void ClearLink ( link_t * l )
{
l - > prev = l - > next = l ;
}
void RemoveLink ( link_t * l )
{
l - > next - > prev = l - > prev ;
l - > prev - > next = l - > next ;
}
void InsertLinkBefore ( link_t * l , link_t * before )
{
l - > next = before ;
l - > prev = before - > prev ;
l - > prev - > next = l ;
l - > next - > prev = l ;
}
2011-12-29 15:10:18 +00:00
2010-02-15 23:26:55 +00:00
void InsertLinkAfter ( link_t * l , link_t * after )
{
l - > next = after - > next ;
l - > prev = after ;
l - > prev - > next = l ;
l - > next - > prev = l ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LIBRARY REPLACEMENT FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2013-09-25 17:01:40 +00:00
int q_strcasecmp ( const char * s1 , const char * s2 )
{
const char * p1 = s1 ;
const char * p2 = s2 ;
char c1 , c2 ;
if ( p1 = = p2 )
return 0 ;
do
{
c1 = q_tolower ( * p1 + + ) ;
c2 = q_tolower ( * p2 + + ) ;
if ( c1 = = ' \0 ' )
break ;
} while ( c1 = = c2 ) ;
return ( int ) ( c1 - c2 ) ;
}
int q_strncasecmp ( const char * s1 , const char * s2 , size_t n )
{
const char * p1 = s1 ;
const char * p2 = s2 ;
char c1 , c2 ;
if ( p1 = = p2 | | n = = 0 )
return 0 ;
do
{
c1 = q_tolower ( * p1 + + ) ;
c2 = q_tolower ( * p2 + + ) ;
if ( c1 = = ' \0 ' | | c1 ! = c2 )
break ;
} while ( - - n > 0 ) ;
return ( int ) ( c1 - c2 ) ;
}
2017-04-02 18:18:57 +00:00
//spike -- grabbed this from fte, because its useful to me
char * q_strcasestr ( const char * haystack , const char * needle )
{
int c1 , c2 , c2f ;
int i ;
c2f = * needle ;
if ( c2f > = ' a ' & & c2f < = ' z ' )
c2f - = ( ' a ' - ' A ' ) ;
if ( ! c2f )
return ( char * ) haystack ;
while ( 1 )
{
c1 = * haystack ;
if ( ! c1 )
return NULL ;
if ( c1 > = ' a ' & & c1 < = ' z ' )
c1 - = ( ' a ' - ' A ' ) ;
if ( c1 = = c2f )
{
for ( i = 1 ; ; i + + )
{
c1 = haystack [ i ] ;
c2 = needle [ i ] ;
if ( c1 > = ' a ' & & c1 < = ' z ' )
c1 - = ( ' a ' - ' A ' ) ;
if ( c2 > = ' a ' & & c2 < = ' z ' )
c2 - = ( ' a ' - ' A ' ) ;
if ( ! c2 )
return ( char * ) haystack ; //end of needle means we found a complete match
if ( ! c1 ) //end of haystack means we can't possibly find needle in it any more
return NULL ;
if ( c1 ! = c2 ) //mismatch means no match starting at haystack[0]
break ;
}
}
haystack + + ;
}
return NULL ; //didn't find it
}
2013-09-25 17:01:40 +00:00
char * q_strlwr ( char * str )
{
char * c ;
c = str ;
while ( * c )
{
* c = q_tolower ( * c ) ;
c + + ;
}
return str ;
}
char * q_strupr ( char * str )
{
char * c ;
c = str ;
while ( * c )
{
* c = q_toupper ( * c ) ;
c + + ;
}
return str ;
}
/* platform dependant (v)snprintf function names: */
# if defined(_WIN32)
# define snprintf_func _snprintf
# define vsnprintf_func _vsnprintf
# else
# define snprintf_func snprintf
# define vsnprintf_func vsnprintf
# endif
2010-08-31 14:09:00 +00:00
int q_vsnprintf ( char * str , size_t size , const char * format , va_list args )
{
int ret ;
ret = vsnprintf_func ( str , size , format , args ) ;
if ( ret < 0 )
ret = ( int ) size ;
2011-12-27 19:32:17 +00:00
if ( size = = 0 ) /* no buffer */
return ret ;
2010-08-31 14:09:00 +00:00
if ( ( size_t ) ret > = size )
str [ size - 1 ] = ' \0 ' ;
return ret ;
}
int q_snprintf ( char * str , size_t size , const char * format , . . . )
{
int ret ;
va_list argptr ;
va_start ( argptr , format ) ;
ret = q_vsnprintf ( str , size , format , argptr ) ;
va_end ( argptr ) ;
return ret ;
}
2010-02-16 21:22:20 +00:00
void Q_memset ( void * dest , int fill , size_t count )
2010-02-15 23:26:55 +00:00
{
2010-02-16 21:22:20 +00:00
size_t i ;
2010-02-15 23:26:55 +00:00
2010-02-16 21:22:20 +00:00
if ( ( ( ( size_t ) dest | count ) & 3 ) = = 0 )
2010-02-15 23:26:55 +00:00
{
count > > = 2 ;
fill = fill | ( fill < < 8 ) | ( fill < < 16 ) | ( fill < < 24 ) ;
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < count ; i + + )
2010-02-15 23:26:55 +00:00
( ( int * ) dest ) [ i ] = fill ;
}
else
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < count ; i + + )
2010-02-15 23:26:55 +00:00
( ( byte * ) dest ) [ i ] = fill ;
}
2010-02-16 21:22:20 +00:00
void Q_memcpy ( void * dest , const void * src , size_t count )
2010-02-15 23:26:55 +00:00
{
2010-02-16 21:22:20 +00:00
size_t i ;
2010-02-15 23:26:55 +00:00
2010-02-16 21:22:20 +00:00
if ( ( ( ( size_t ) dest | ( size_t ) src | count ) & 3 ) = = 0 )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
count > > = 2 ;
for ( i = 0 ; i < count ; i + + )
2010-02-15 23:26:55 +00:00
( ( int * ) dest ) [ i ] = ( ( int * ) src ) [ i ] ;
}
else
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < count ; i + + )
2010-02-15 23:26:55 +00:00
( ( byte * ) dest ) [ i ] = ( ( byte * ) src ) [ i ] ;
}
2010-02-16 21:22:20 +00:00
int Q_memcmp ( const void * m1 , const void * m2 , size_t count )
2010-02-15 23:26:55 +00:00
{
while ( count )
{
count - - ;
if ( ( ( byte * ) m1 ) [ count ] ! = ( ( byte * ) m2 ) [ count ] )
return - 1 ;
}
return 0 ;
}
2010-02-16 13:02:22 +00:00
void Q_strcpy ( char * dest , const char * src )
2010-02-15 23:26:55 +00:00
{
while ( * src )
{
* dest + + = * src + + ;
}
* dest + + = 0 ;
}
2010-02-16 13:02:22 +00:00
void Q_strncpy ( char * dest , const char * src , int count )
2010-02-15 23:26:55 +00:00
{
while ( * src & & count - - )
{
* dest + + = * src + + ;
}
if ( count )
* dest + + = 0 ;
}
2010-02-16 13:02:22 +00:00
int Q_strlen ( const char * str )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int count ;
2010-02-15 23:26:55 +00:00
count = 0 ;
while ( str [ count ] )
count + + ;
return count ;
}
2010-02-16 13:02:22 +00:00
char * Q_strrchr ( const char * s , char c )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int len = Q_strlen ( s ) ;
s + = len ;
while ( len - - )
{
if ( * - - s = = c )
return ( char * ) s ;
}
return NULL ;
2010-02-15 23:26:55 +00:00
}
2010-02-16 13:02:22 +00:00
void Q_strcat ( char * dest , const char * src )
2010-02-15 23:26:55 +00:00
{
dest + = Q_strlen ( dest ) ;
Q_strcpy ( dest , src ) ;
}
2010-02-16 13:02:22 +00:00
int Q_strcmp ( const char * s1 , const char * s2 )
2010-02-15 23:26:55 +00:00
{
while ( 1 )
{
if ( * s1 ! = * s2 )
2011-12-28 23:40:27 +00:00
return - 1 ; // strings not equal
2010-02-15 23:26:55 +00:00
if ( ! * s1 )
2011-12-28 23:40:27 +00:00
return 0 ; // strings are equal
2010-02-15 23:26:55 +00:00
s1 + + ;
s2 + + ;
}
return - 1 ;
}
2010-02-16 13:02:22 +00:00
int Q_strncmp ( const char * s1 , const char * s2 , int count )
2010-02-15 23:26:55 +00:00
{
while ( 1 )
{
if ( ! count - - )
return 0 ;
if ( * s1 ! = * s2 )
2011-12-28 23:40:27 +00:00
return - 1 ; // strings not equal
2010-02-15 23:26:55 +00:00
if ( ! * s1 )
2011-12-28 23:40:27 +00:00
return 0 ; // strings are equal
2010-02-15 23:26:55 +00:00
s1 + + ;
s2 + + ;
}
return - 1 ;
}
2010-02-16 13:02:22 +00:00
int Q_atoi ( const char * str )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int val ;
int sign ;
int c ;
2010-02-15 23:26:55 +00:00
if ( * str = = ' - ' )
{
sign = - 1 ;
str + + ;
}
else
sign = 1 ;
val = 0 ;
//
// check for hex
//
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' x ' | | str [ 1 ] = = ' X ' ) )
{
str + = 2 ;
while ( 1 )
{
c = * str + + ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
val = ( val < < 4 ) + c - ' 0 ' ;
else if ( c > = ' a ' & & c < = ' f ' )
val = ( val < < 4 ) + c - ' a ' + 10 ;
else if ( c > = ' A ' & & c < = ' F ' )
val = ( val < < 4 ) + c - ' A ' + 10 ;
else
return val * sign ;
}
}
//
// check for character
//
if ( str [ 0 ] = = ' \' ' )
{
return sign * str [ 1 ] ;
}
//
// assume decimal
//
while ( 1 )
{
c = * str + + ;
if ( c < ' 0 ' | | c > ' 9 ' )
return val * sign ;
val = val * 10 + c - ' 0 ' ;
}
return 0 ;
}
2010-02-16 13:02:22 +00:00
float Q_atof ( const char * str )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
double val ;
int sign ;
int c ;
int decimal , total ;
2010-02-15 23:26:55 +00:00
if ( * str = = ' - ' )
{
sign = - 1 ;
str + + ;
}
else
sign = 1 ;
val = 0 ;
//
// check for hex
//
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' x ' | | str [ 1 ] = = ' X ' ) )
{
str + = 2 ;
while ( 1 )
{
c = * str + + ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
val = ( val * 16 ) + c - ' 0 ' ;
else if ( c > = ' a ' & & c < = ' f ' )
val = ( val * 16 ) + c - ' a ' + 10 ;
else if ( c > = ' A ' & & c < = ' F ' )
val = ( val * 16 ) + c - ' A ' + 10 ;
else
return val * sign ;
}
}
//
// check for character
//
if ( str [ 0 ] = = ' \' ' )
{
return sign * str [ 1 ] ;
}
//
// assume decimal
//
decimal = - 1 ;
total = 0 ;
while ( 1 )
{
c = * str + + ;
if ( c = = ' . ' )
{
decimal = total ;
continue ;
}
if ( c < ' 0 ' | | c > ' 9 ' )
break ;
val = val * 10 + c - ' 0 ' ;
total + + ;
}
if ( decimal = = - 1 )
return val * sign ;
while ( total > decimal )
{
val / = 10 ;
total - - ;
}
return val * sign ;
}
2020-07-02 19:05:51 +00:00
// Q_ftoa: convert IEEE 754 float to a base-10 string with "infinite" decimal places
void Q_ftoa ( char * str , float in )
{
2020-07-19 00:36:32 +00:00
struct {
float f ;
unsigned int i ;
} u = { in } ;
2020-07-02 19:05:51 +00:00
2020-07-19 00:36:32 +00:00
int signbit = ( u . i & 0x80000000 ) > > 31 ;
int exp = ( signed int ) ( ( u . i & 0x7F800000 ) > > 23 ) - 127 ;
int mantissa = ( u . i & 0x007FFFFF ) ;
2020-07-02 19:05:51 +00:00
if ( exp = = 128 ) // 255(NaN/Infinity bits) - 127(bias)
{
if ( signbit )
{
* str = ' - ' ;
str + + ;
}
if ( mantissa = = 0 ) // infinity
strcpy ( str , " 1.#INF " ) ;
else // NaN or indeterminate
strcpy ( str , " 1.#NAN " ) ;
return ;
}
exp = - exp ;
exp = ( int ) ( exp * 0.30102999957f ) ; // convert base 2 to base 10
exp + = 8 ;
if ( exp < = 0 )
sprintf ( str , " %.0f " , in ) ;
else
{
char tstr [ 32 ] ;
char * lsig = str - 1 ;
sprintf ( tstr , " %%.%if " , exp ) ;
sprintf ( str , tstr , in ) ;
// find last significant digit and trim
while ( * str )
{
if ( * str > = ' 1 ' & & * str < = ' 9 ' )
lsig = str ;
else if ( * str = = ' . ' )
lsig = str - 1 ;
str + + ;
}
lsig [ 1 ] = ' \0 ' ;
}
}
2020-07-19 00:36:32 +00:00
int wildcmp ( const char * wild , const char * string )
{ //case-insensitive string compare with wildcards. returns true for a match.
while ( * string )
{
if ( * wild = = ' * ' )
{
if ( * string = = ' / ' | | * string = = ' \\ ' )
{
//* terminates if we get a match on the char following it, or if its a \ or / char
wild + + ;
continue ;
}
if ( wildcmp ( wild + 1 , string ) )
return true ;
string + + ;
}
else if ( ( q_tolower ( * wild ) = = q_tolower ( * string ) ) | | ( * wild = = ' ? ' ) )
{
//this char matches
wild + + ;
string + + ;
}
else
{
//failure
return false ;
}
}
while ( * wild = = ' * ' )
{
wild + + ;
}
return ! * wild ;
}
2020-09-02 08:43:25 +00:00
void Info_RemoveKey ( char * info , const char * key )
{ //only shrinks, so no need for max size.
size_t keylen = strlen ( key ) ;
while ( * info )
{
char * l = info ;
if ( * info + + ! = ' \\ ' )
break ; //error / end-of-string
if ( ! strncmp ( info , key , keylen ) & & info [ keylen ] = = ' \\ ' )
{
//skip the key name
info + = keylen + 1 ;
//this is the old value for the key. skip over it
while ( * info & & * info ! = ' \\ ' )
info + + ;
//okay, we found it. strip it out now.
memmove ( l , info , strlen ( info ) + 1 ) ;
return ;
}
else
{
//skip the key
while ( * info & & * info ! = ' \\ ' )
info + + ;
//validate that its a value now
if ( * info + + ! = ' \\ ' )
break ; //error
//skip the value
while ( * info & & * info ! = ' \\ ' )
info + + ;
}
}
}
void Info_SetKey ( char * info , size_t infosize , const char * key , const char * val )
{
size_t keylen = strlen ( key ) ;
size_t vallen = strlen ( val ) ;
Info_RemoveKey ( info , key ) ;
if ( vallen )
{
char * o = info + strlen ( info ) ;
char * e = info + infosize - 1 ;
if ( ! * key | | strchr ( key , ' \\ ' ) | | strchr ( val , ' \\ ' ) )
Con_Warning ( " Info_SetKey(%s): invalid key/value \n " , key ) ;
else if ( o + 2 + keylen + vallen > = e )
Con_Warning ( " Info_SetKey(%s): length exceeds max \n " , key ) ;
else
{
* o + + = ' \\ ' ;
memcpy ( o , key , keylen ) ;
o + = keylen ;
* o + + = ' \\ ' ;
memcpy ( o , val , vallen ) ;
o + = vallen ;
* o = 0 ;
}
}
}
const char * Info_GetKey ( const char * info , const char * key , char * out , size_t outsize )
{
const char * r = out ;
size_t keylen = strlen ( key ) ;
outsize - - ;
while ( * info )
{
if ( * info + + ! = ' \\ ' )
break ; //error / end-of-string
if ( ! strncmp ( info , key , keylen ) & & info [ keylen ] = = ' \\ ' )
{
//skip the key name
info + = keylen + 1 ;
//this is the value for the key. copy it out
while ( * info & & * info ! = ' \\ ' & & outsize - - > 0 )
* out + + = * info + + ;
break ;
}
else
{
//skip the key
while ( * info & & * info ! = ' \\ ' )
info + + ;
//validate that its a value now
if ( * info + + ! = ' \\ ' )
break ; //error
//skip the value
while ( * info & & * info ! = ' \\ ' )
info + + ;
}
}
* out = 0 ;
return r ;
}
void Info_Enumerate ( const char * info , void ( * cb ) ( void * ctx , const char * key , const char * value ) , void * cbctx )
{
char key [ 1024 ] ;
char val [ 1024 ] ;
size_t kl , vl ;
while ( * info )
{
kl = vl = 0 ;
if ( * info + + ! = ' \\ ' )
break ; //error / end-of-string
//skip the key
while ( * info & & * info ! = ' \\ ' )
{
if ( kl < sizeof ( key ) - 1 )
key [ kl + + ] = * info ;
info + + ;
}
//validate that its a value now
if ( * info + + ! = ' \\ ' )
break ; //error
//skip the value
while ( * info & & * info ! = ' \\ ' )
{
if ( vl < sizeof ( val ) - 1 )
val [ vl + + ] = * info ;
info + + ;
}
key [ kl ] = 0 ;
val [ vl ] = 0 ;
cb ( cbctx , key , val ) ;
}
}
static void Info_Print_Callback ( void * ctx , const char * key , const char * val )
{
Con_Printf ( " %20s: %s \n " , key , val ) ;
}
void Info_Print ( const char * info )
{
Info_Enumerate ( info , Info_Print_Callback , NULL ) ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BYTE ORDER FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-06-12 12:25:22 +00:00
qboolean host_bigendian ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
short ( * BigShort ) ( short l ) ;
short ( * LittleShort ) ( short l ) ;
int ( * BigLong ) ( int l ) ;
int ( * LittleLong ) ( int l ) ;
float ( * BigFloat ) ( float l ) ;
float ( * LittleFloat ) ( float l ) ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
short ShortSwap ( short l )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
byte b1 , b2 ;
2010-02-15 23:26:55 +00:00
b1 = l & 255 ;
b2 = ( l > > 8 ) & 255 ;
return ( b1 < < 8 ) + b2 ;
}
2011-12-28 23:40:27 +00:00
short ShortNoSwap ( short l )
2010-02-15 23:26:55 +00:00
{
return l ;
}
2011-12-28 23:40:27 +00:00
int LongSwap ( int l )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
byte b1 , b2 , b3 , b4 ;
2010-02-15 23:26:55 +00:00
b1 = l & 255 ;
b2 = ( l > > 8 ) & 255 ;
b3 = ( l > > 16 ) & 255 ;
b4 = ( l > > 24 ) & 255 ;
return ( ( int ) b1 < < 24 ) + ( ( int ) b2 < < 16 ) + ( ( int ) b3 < < 8 ) + b4 ;
}
2011-12-28 23:40:27 +00:00
int LongNoSwap ( int l )
2010-02-15 23:26:55 +00:00
{
return l ;
}
float FloatSwap ( float f )
{
union
{
2011-12-28 23:40:27 +00:00
float f ;
byte b [ 4 ] ;
2010-02-15 23:26:55 +00:00
} dat1 , dat2 ;
dat1 . f = f ;
dat2 . b [ 0 ] = dat1 . b [ 3 ] ;
dat2 . b [ 1 ] = dat1 . b [ 2 ] ;
dat2 . b [ 2 ] = dat1 . b [ 1 ] ;
dat2 . b [ 3 ] = dat1 . b [ 0 ] ;
return dat2 . f ;
}
float FloatNoSwap ( float f )
{
return f ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
MESSAGE IO FUNCTIONS
Handles byte ordering and avoids alignment errors
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//
// writing functions
//
void MSG_WriteChar ( sizebuf_t * sb , int c )
{
2011-12-28 23:40:27 +00:00
byte * buf ;
2010-02-15 23:26:55 +00:00
# ifdef PARANOID
if ( c < - 128 | | c > 127 )
Sys_Error ( " MSG_WriteChar: range error " ) ;
# endif
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) SZ_GetSpace ( sb , 1 ) ;
2010-02-15 23:26:55 +00:00
buf [ 0 ] = c ;
}
void MSG_WriteByte ( sizebuf_t * sb , int c )
{
2011-12-28 23:40:27 +00:00
byte * buf ;
2010-02-15 23:26:55 +00:00
# ifdef PARANOID
if ( c < 0 | | c > 255 )
Sys_Error ( " MSG_WriteByte: range error " ) ;
# endif
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) SZ_GetSpace ( sb , 1 ) ;
2010-02-15 23:26:55 +00:00
buf [ 0 ] = c ;
}
void MSG_WriteShort ( sizebuf_t * sb , int c )
{
2011-12-28 23:40:27 +00:00
byte * buf ;
2010-02-15 23:26:55 +00:00
# ifdef PARANOID
if ( c < ( ( short ) 0x8000 ) | | c > ( short ) 0x7fff )
Sys_Error ( " MSG_WriteShort: range error " ) ;
# endif
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) SZ_GetSpace ( sb , 2 ) ;
2010-02-15 23:26:55 +00:00
buf [ 0 ] = c & 0xff ;
buf [ 1 ] = c > > 8 ;
}
void MSG_WriteLong ( sizebuf_t * sb , int c )
{
2011-12-28 23:40:27 +00:00
byte * buf ;
2010-02-15 23:26:55 +00:00
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) SZ_GetSpace ( sb , 4 ) ;
2010-02-15 23:26:55 +00:00
buf [ 0 ] = c & 0xff ;
buf [ 1 ] = ( c > > 8 ) & 0xff ;
buf [ 2 ] = ( c > > 16 ) & 0xff ;
buf [ 3 ] = c > > 24 ;
}
void MSG_WriteFloat ( sizebuf_t * sb , float f )
{
union
{
2011-12-28 23:40:27 +00:00
float f ;
int l ;
2010-02-15 23:26:55 +00:00
} dat ;
dat . f = f ;
dat . l = LittleLong ( dat . l ) ;
SZ_Write ( sb , & dat . l , 4 ) ;
}
2010-08-29 02:22:55 +00:00
void MSG_WriteString ( sizebuf_t * sb , const char * s )
2010-02-15 23:26:55 +00:00
{
if ( ! s )
SZ_Write ( sb , " " , 1 ) ;
else
SZ_Write ( sb , s , Q_strlen ( s ) + 1 ) ;
}
//johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096
void MSG_WriteCoord16 ( sizebuf_t * sb , float f )
{
MSG_WriteShort ( sb , Q_rint ( f * 8 ) ) ;
}
//johnfitz -- 16.8 fixed point coords, max range +-32768
void MSG_WriteCoord24 ( sizebuf_t * sb , float f )
{
MSG_WriteShort ( sb , f ) ;
MSG_WriteByte ( sb , ( int ) ( f * 255 ) % 255 ) ;
}
//johnfitz -- 32-bit float coords
void MSG_WriteCoord32f ( sizebuf_t * sb , float f )
{
MSG_WriteFloat ( sb , f ) ;
}
2016-06-24 06:15:41 +00:00
void MSG_WriteCoord ( sizebuf_t * sb , float f , unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATCOORD )
MSG_WriteFloat ( sb , f ) ;
else if ( flags & PRFL_INT32COORD )
MSG_WriteLong ( sb , Q_rint ( f * 16 ) ) ;
else if ( flags & PRFL_24BITCOORD )
MSG_WriteCoord24 ( sb , f ) ;
else MSG_WriteCoord16 ( sb , f ) ;
2010-02-15 23:26:55 +00:00
}
2016-06-24 06:15:41 +00:00
void MSG_WriteAngle ( sizebuf_t * sb , float f , unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATANGLE )
MSG_WriteFloat ( sb , f ) ;
else if ( flags & PRFL_SHORTANGLE )
MSG_WriteShort ( sb , Q_rint ( f * 65536.0 / 360.0 ) & 65535 ) ;
else MSG_WriteByte ( sb , Q_rint ( f * 256.0 / 360.0 ) & 255 ) ; //johnfitz -- use Q_rint instead of (int) }
2010-02-15 23:26:55 +00:00
}
//johnfitz -- for PROTOCOL_FITZQUAKE
2016-06-24 06:15:41 +00:00
void MSG_WriteAngle16 ( sizebuf_t * sb , float f , unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATANGLE )
MSG_WriteFloat ( sb , f ) ;
else MSG_WriteShort ( sb , Q_rint ( f * 65536.0 / 360.0 ) & 65535 ) ;
2010-02-15 23:26:55 +00:00
}
//johnfitz
2020-06-19 22:11:22 +00:00
//spike -- for PEXT2_REPLACEMENTDELTAS
void MSG_WriteEntity ( sizebuf_t * sb , unsigned int entnum , unsigned int pext2 )
{
//high short, low byte
if ( entnum > 0x7fff & & ( pext2 & PEXT2_REPLACEMENTDELTAS ) )
{
MSG_WriteShort ( sb , 0x8000 | ( entnum > > 8 ) ) ;
MSG_WriteByte ( sb , entnum & 0xff ) ;
}
else
MSG_WriteShort ( sb , entnum ) ;
}
2010-02-15 23:26:55 +00:00
//
// reading functions
//
2011-12-28 23:40:27 +00:00
int msg_readcount ;
qboolean msg_badread ;
2010-02-15 23:26:55 +00:00
void MSG_BeginReading ( void )
{
msg_readcount = 0 ;
msg_badread = false ;
}
// returns -1 and sets msg_badread if no more characters are available
int MSG_ReadChar ( void )
{
2011-12-28 23:40:27 +00:00
int c ;
2010-02-15 23:26:55 +00:00
if ( msg_readcount + 1 > net_message . cursize )
{
msg_badread = true ;
return - 1 ;
}
c = ( signed char ) net_message . data [ msg_readcount ] ;
msg_readcount + + ;
return c ;
}
int MSG_ReadByte ( void )
{
2011-12-28 23:40:27 +00:00
int c ;
2010-02-15 23:26:55 +00:00
if ( msg_readcount + 1 > net_message . cursize )
{
msg_badread = true ;
return - 1 ;
}
c = ( unsigned char ) net_message . data [ msg_readcount ] ;
msg_readcount + + ;
return c ;
}
int MSG_ReadShort ( void )
{
2011-12-28 23:40:27 +00:00
int c ;
2010-02-15 23:26:55 +00:00
if ( msg_readcount + 2 > net_message . cursize )
{
msg_badread = true ;
return - 1 ;
}
c = ( short ) ( net_message . data [ msg_readcount ]
2013-01-16 19:02:23 +00:00
+ ( net_message . data [ msg_readcount + 1 ] < < 8 ) ) ;
2010-02-15 23:26:55 +00:00
msg_readcount + = 2 ;
return c ;
}
int MSG_ReadLong ( void )
{
2011-12-28 23:40:27 +00:00
int c ;
2010-02-15 23:26:55 +00:00
if ( msg_readcount + 4 > net_message . cursize )
{
msg_badread = true ;
return - 1 ;
}
c = net_message . data [ msg_readcount ]
2013-01-16 19:02:23 +00:00
+ ( net_message . data [ msg_readcount + 1 ] < < 8 )
+ ( net_message . data [ msg_readcount + 2 ] < < 16 )
+ ( net_message . data [ msg_readcount + 3 ] < < 24 ) ;
2010-02-15 23:26:55 +00:00
msg_readcount + = 4 ;
return c ;
}
float MSG_ReadFloat ( void )
{
union
{
2011-12-28 23:40:27 +00:00
byte b [ 4 ] ;
float f ;
int l ;
2010-02-15 23:26:55 +00:00
} dat ;
2011-12-28 23:40:27 +00:00
dat . b [ 0 ] = net_message . data [ msg_readcount ] ;
dat . b [ 1 ] = net_message . data [ msg_readcount + 1 ] ;
dat . b [ 2 ] = net_message . data [ msg_readcount + 2 ] ;
dat . b [ 3 ] = net_message . data [ msg_readcount + 3 ] ;
2010-02-15 23:26:55 +00:00
msg_readcount + = 4 ;
dat . l = LittleLong ( dat . l ) ;
return dat . f ;
}
2010-08-29 02:22:55 +00:00
const char * MSG_ReadString ( void )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
static char string [ 2048 ] ;
2011-12-29 19:06:08 +00:00
int c ;
size_t l ;
2010-02-15 23:26:55 +00:00
l = 0 ;
do
{
2015-08-05 14:47:25 +00:00
c = MSG_ReadByte ( ) ;
2010-02-15 23:26:55 +00:00
if ( c = = - 1 | | c = = 0 )
break ;
string [ l ] = c ;
l + + ;
2011-12-29 19:06:08 +00:00
} while ( l < sizeof ( string ) - 1 ) ;
2010-02-15 23:26:55 +00:00
string [ l ] = 0 ;
return string ;
}
//johnfitz -- original behavior, 13.3 fixed point coords, max range +-4096
float MSG_ReadCoord16 ( void )
{
return MSG_ReadShort ( ) * ( 1.0 / 8 ) ;
}
//johnfitz -- 16.8 fixed point coords, max range +-32768
float MSG_ReadCoord24 ( void )
{
return MSG_ReadShort ( ) + MSG_ReadByte ( ) * ( 1.0 / 255 ) ;
}
//johnfitz -- 32-bit float coords
float MSG_ReadCoord32f ( void )
{
return MSG_ReadFloat ( ) ;
}
2016-06-24 06:15:41 +00:00
float MSG_ReadCoord ( unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATCOORD )
return MSG_ReadFloat ( ) ;
else if ( flags & PRFL_INT32COORD )
return MSG_ReadLong ( ) * ( 1.0 / 16.0 ) ;
else if ( flags & PRFL_24BITCOORD )
return MSG_ReadCoord24 ( ) ;
else return MSG_ReadCoord16 ( ) ;
2010-02-15 23:26:55 +00:00
}
2016-06-24 06:15:41 +00:00
float MSG_ReadAngle ( unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATANGLE )
return MSG_ReadFloat ( ) ;
else if ( flags & PRFL_SHORTANGLE )
return MSG_ReadShort ( ) * ( 360.0 / 65536 ) ;
else return MSG_ReadChar ( ) * ( 360.0 / 256 ) ;
2010-02-15 23:26:55 +00:00
}
//johnfitz -- for PROTOCOL_FITZQUAKE
2016-06-24 06:15:41 +00:00
float MSG_ReadAngle16 ( unsigned int flags )
2010-02-15 23:26:55 +00:00
{
2016-06-24 06:15:41 +00:00
if ( flags & PRFL_FLOATANGLE )
return MSG_ReadFloat ( ) ; // make sure
else return MSG_ReadShort ( ) * ( 360.0 / 65536 ) ;
2010-02-15 23:26:55 +00:00
}
//johnfitz
2020-06-19 22:11:22 +00:00
unsigned int MSG_ReadEntity ( unsigned int pext2 )
2018-05-01 00:35:14 +00:00
{
2020-06-19 22:11:22 +00:00
unsigned int e = ( unsigned short ) MSG_ReadShort ( ) ;
2018-05-01 00:35:14 +00:00
if ( pext2 & PEXT2_REPLACEMENTDELTAS )
{
if ( e & 0x8000 )
{
e = ( e & 0x7fff ) < < 8 ;
e | = MSG_ReadByte ( ) ;
}
}
return e ;
}
2017-09-17 02:12:53 +00:00
//spike -- for downloads
byte * MSG_ReadData ( unsigned int length )
{
byte * data ;
if ( msg_readcount + length > ( unsigned int ) net_message . cursize )
{
msg_badread = true ;
return NULL ;
}
data = net_message . data + msg_readcount ;
msg_readcount + = length ;
return data ;
}
2010-02-15 23:26:55 +00:00
//===========================================================================
void SZ_Alloc ( sizebuf_t * buf , int startsize )
{
if ( startsize < 256 )
startsize = 256 ;
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf - > data = ( byte * ) Hunk_AllocName ( startsize , " sizebuf " ) ;
2010-02-15 23:26:55 +00:00
buf - > maxsize = startsize ;
buf - > cursize = 0 ;
}
void SZ_Free ( sizebuf_t * buf )
{
2011-12-28 23:40:27 +00:00
// Z_Free (buf->data);
// buf->data = NULL;
// buf->maxsize = 0;
2010-02-15 23:26:55 +00:00
buf - > cursize = 0 ;
}
void SZ_Clear ( sizebuf_t * buf )
{
buf - > cursize = 0 ;
2017-09-17 02:12:53 +00:00
buf - > overflowed = false ;
2010-02-15 23:26:55 +00:00
}
void * SZ_GetSpace ( sizebuf_t * buf , int length )
{
2011-12-28 23:40:27 +00:00
void * data ;
2010-02-15 23:26:55 +00:00
if ( buf - > cursize + length > buf - > maxsize )
{
if ( ! buf - > allowoverflow )
2017-09-12 23:12:33 +00:00
Host_Error ( " SZ_GetSpace: overflow without allowoverflow set " ) ; // ericw -- made Host_Error to be less annoying
2010-02-15 23:26:55 +00:00
if ( length > buf - > maxsize )
Sys_Error ( " SZ_GetSpace: %i is > full buffer size " , length ) ;
2017-09-17 02:12:53 +00:00
Con_Printf ( " SZ_GetSpace: overflow \n " ) ;
2010-02-15 23:26:55 +00:00
SZ_Clear ( buf ) ;
2017-09-17 02:12:53 +00:00
buf - > overflowed = true ;
2010-02-15 23:26:55 +00:00
}
data = buf - > data + buf - > cursize ;
buf - > cursize + = length ;
return data ;
}
2010-08-29 02:22:55 +00:00
void SZ_Write ( sizebuf_t * buf , const void * data , int length )
2010-02-15 23:26:55 +00:00
{
Q_memcpy ( SZ_GetSpace ( buf , length ) , data , length ) ;
}
2010-08-29 02:22:55 +00:00
void SZ_Print ( sizebuf_t * buf , const char * data )
2010-02-15 23:26:55 +00:00
{
2013-01-16 19:02:23 +00:00
int len = Q_strlen ( data ) + 1 ;
2010-02-15 23:26:55 +00:00
if ( buf - > data [ buf - > cursize - 1 ] )
2013-01-16 19:02:23 +00:00
{ /* no trailing 0 */
Q_memcpy ( ( byte * ) SZ_GetSpace ( buf , len ) , data , len ) ;
}
2010-02-15 23:26:55 +00:00
else
2013-01-16 19:02:23 +00:00
{ /* write over trailing 0 */
Q_memcpy ( ( byte * ) SZ_GetSpace ( buf , len - 1 ) - 1 , data , len ) ;
}
2010-02-15 23:26:55 +00:00
}
//============================================================================
/*
= = = = = = = = = = = =
COM_SkipPath
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
const char * COM_SkipPath ( const char * pathname )
2010-02-15 23:26:55 +00:00
{
2011-12-27 08:04:02 +00:00
const char * last ;
2010-02-15 23:26:55 +00:00
last = pathname ;
while ( * pathname )
{
2011-12-27 08:04:02 +00:00
if ( * pathname = = ' / ' )
last = pathname + 1 ;
2010-02-15 23:26:55 +00:00
pathname + + ;
}
return last ;
}
/*
= = = = = = = = = = = =
COM_StripExtension
= = = = = = = = = = = =
*/
2011-12-27 08:04:02 +00:00
void COM_StripExtension ( const char * in , char * out , size_t outsize )
2010-02-15 23:26:55 +00:00
{
2011-12-27 08:04:02 +00:00
int length ;
if ( ! * in )
{
* out = ' \0 ' ;
return ;
}
if ( in ! = out ) /* copy when not in-place editing */
2011-12-27 13:15:31 +00:00
q_strlcpy ( out , in , outsize ) ;
2011-12-27 08:04:02 +00:00
length = ( int ) strlen ( out ) - 1 ;
while ( length > 0 & & out [ length ] ! = ' . ' )
{
- - length ;
if ( out [ length ] = = ' / ' | | out [ length ] = = ' \\ ' )
return ; /* no extension */
}
if ( length > 0 )
out [ length ] = ' \0 ' ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
2011-05-20 20:38:11 +00:00
COM_FileGetExtension - doesn ' t return NULL
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = =
*/
2011-05-20 20:38:11 +00:00
const char * COM_FileGetExtension ( const char * in )
2010-02-15 23:26:55 +00:00
{
2011-05-20 20:38:11 +00:00
const char * src ;
size_t len ;
2010-02-15 23:26:55 +00:00
2011-05-20 20:38:11 +00:00
len = strlen ( in ) ;
if ( len < 2 ) /* nothing meaningful */
2010-02-15 23:26:55 +00:00
return " " ;
2011-05-20 20:38:11 +00:00
src = in + len - 1 ;
while ( src ! = in & & src [ - 1 ] ! = ' . ' )
src - - ;
if ( src = = in | | strchr ( src , ' / ' ) ! = NULL | | strchr ( src , ' \\ ' ) ! = NULL )
return " " ; /* no extension, or parent directory has a dot */
return src ;
2010-02-15 23:26:55 +00:00
}
2011-12-27 14:00:33 +00:00
/*
= = = = = = = = = = = =
COM_ExtractExtension
= = = = = = = = = = = =
*/
void COM_ExtractExtension ( const char * in , char * out , size_t outsize )
{
const char * ext = COM_FileGetExtension ( in ) ;
if ( ! * ext )
* out = ' \0 ' ;
else
q_strlcpy ( out , ext , outsize ) ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = =
COM_FileBase
2011-12-27 08:04:02 +00:00
take ' somedir / otherdir / filename . ext ' ,
write only ' filename ' to the output
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = =
*/
2011-12-27 08:04:02 +00:00
void COM_FileBase ( const char * in , char * out , size_t outsize )
2010-02-15 23:26:55 +00:00
{
2011-12-27 08:04:02 +00:00
const char * dot , * slash , * s ;
2010-02-15 23:26:55 +00:00
2011-12-27 08:04:02 +00:00
s = in ;
slash = in ;
dot = NULL ;
while ( * s )
{
if ( * s = = ' / ' )
slash = s + 1 ;
if ( * s = = ' . ' )
dot = s ;
s + + ;
}
if ( dot = = NULL )
dot = s ;
2010-02-15 23:26:55 +00:00
2011-12-27 08:04:02 +00:00
if ( dot - slash < 2 )
2011-12-27 13:15:31 +00:00
q_strlcpy ( out , " ?model? " , outsize ) ;
2010-02-15 23:26:55 +00:00
else
{
2011-12-27 08:04:02 +00:00
size_t len = dot - slash ;
if ( len > = outsize )
len = outsize - 1 ;
memcpy ( out , slash , len ) ;
out [ len ] = ' \0 ' ;
2010-02-15 23:26:55 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = =
COM_DefaultExtension
2014-04-26 07:50:54 +00:00
if path doesn ' t have a . EXT , append extension
( extension should include the leading " . " )
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = = = = = = = =
*/
2014-04-27 08:33:05 +00:00
#if 0 /* can be dangerous */
2011-12-27 08:04:02 +00:00
void COM_DefaultExtension ( char * path , const char * extension , size_t len )
2010-02-15 23:26:55 +00:00
{
2011-12-27 08:04:02 +00:00
char * src ;
2010-02-15 23:26:55 +00:00
2014-04-26 07:50:54 +00:00
if ( ! * path ) return ;
src = path + strlen ( path ) - 1 ;
while ( * src ! = ' / ' & & * src ! = ' \\ ' & & src ! = path )
2010-02-15 23:26:55 +00:00
{
if ( * src = = ' . ' )
2014-04-26 07:50:54 +00:00
return ; // it has an extension
2010-02-15 23:26:55 +00:00
src - - ;
}
2011-12-27 13:15:31 +00:00
q_strlcat ( path , extension , len ) ;
2014-04-26 07:50:54 +00:00
}
2014-04-27 08:33:05 +00:00
# endif
2014-04-26 07:50:54 +00:00
/*
= = = = = = = = = = = = = = = = = =
COM_AddExtension
if path extension doesn ' t match . EXT , append it
( extension should include the leading " . " )
= = = = = = = = = = = = = = = = = =
*/
void COM_AddExtension ( char * path , const char * extension , size_t len )
{
if ( strcmp ( COM_FileGetExtension ( path ) , extension + 1 ) ! = 0 )
q_strlcat ( path , extension , len ) ;
2010-02-15 23:26:55 +00:00
}
2017-09-17 02:12:53 +00:00
/*
spike - - this function simply says whether a filename is acceptable for downloading ( used by both client + server )
*/
qboolean COM_DownloadNameOkay ( const char * filename )
{
if ( ! allow_download . value )
return false ;
//quickly test the prefix to ensure that its in one of the allowed subdirs
if ( strncmp ( filename , " sound/ " , 6 ) & &
strncmp ( filename , " progs/ " , 6 ) & &
strncmp ( filename , " maps/ " , 5 ) & &
strncmp ( filename , " models/ " , 7 ) )
return false ;
//windows paths are NOT permitted, nor are alternative data streams, nor wildcards, and double quotes are always bad(which allows for spaces)
if ( strchr ( filename , ' \\ ' ) | | strchr ( filename , ' : ' ) | | strchr ( filename , ' * ' ) | | strchr ( filename , ' ? ' ) | | strchr ( filename , ' \" ' ) )
return false ;
//some operating systems interpret this as 'parent directory'
if ( strstr ( filename , " // " ) )
return false ;
//block unix hidden files, also blocks relative paths.
if ( * filename = = ' . ' | | strstr ( filename , " /. " ) )
return false ;
//test the extension to ensure that its in one of the allowed file types
//(no .dll, .so, .com, .exe, .bat, .vbs, .xls, .doc, etc please)
//also don't allow config files.
filename = COM_FileGetExtension ( filename ) ;
if (
//model formats
q_strcasecmp ( filename , " bsp " ) & &
q_strcasecmp ( filename , " mdl " ) & &
q_strcasecmp ( filename , " iqm " ) & & //in case we ever support these later
2018-05-05 15:21:09 +00:00
q_strcasecmp ( filename , " md3 " ) & &
2017-09-17 02:12:53 +00:00
q_strcasecmp ( filename , " spr " ) & &
q_strcasecmp ( filename , " spr32 " ) & &
//audio formats
q_strcasecmp ( filename , " wav " ) & &
q_strcasecmp ( filename , " ogg " ) & &
//image formats (if we ever need that)
q_strcasecmp ( filename , " tga " ) & &
q_strcasecmp ( filename , " png " ) & &
//misc stuff
q_strcasecmp ( filename , " lux " ) & &
q_strcasecmp ( filename , " lit2 " ) & &
q_strcasecmp ( filename , " lit " ) )
return false ;
//okay, well, we didn't throw a hissy fit, so whatever dude, go ahead and download
return true ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = =
COM_Parse
Parse a token out of a string
= = = = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
const char * COM_Parse ( const char * data )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int c ;
int len ;
2010-02-15 23:26:55 +00:00
len = 0 ;
com_token [ 0 ] = 0 ;
if ( ! data )
return NULL ;
// skip whitespace
skipwhite :
2013-01-16 19:02:23 +00:00
while ( ( c = * data ) < = ' ' )
2010-02-15 23:26:55 +00:00
{
if ( c = = 0 )
2013-01-16 19:02:23 +00:00
return NULL ; // end of file
2010-02-15 23:26:55 +00:00
data + + ;
}
// skip // comments
2013-01-16 19:02:23 +00:00
if ( c = = ' / ' & & data [ 1 ] = = ' / ' )
2010-02-15 23:26:55 +00:00
{
while ( * data & & * data ! = ' \n ' )
data + + ;
goto skipwhite ;
}
2013-01-16 19:02:23 +00:00
// skip /*..*/ comments
if ( c = = ' / ' & & data [ 1 ] = = ' * ' )
{
data + = 2 ;
while ( * data & & ! ( * data = = ' * ' & & data [ 1 ] = = ' / ' ) )
data + + ;
if ( * data )
data + = 2 ;
goto skipwhite ;
}
2010-02-15 23:26:55 +00:00
// handle quoted strings specially
if ( c = = ' \" ' )
{
data + + ;
while ( 1 )
{
2013-01-16 19:02:23 +00:00
if ( ( c = * data ) ! = 0 )
+ + data ;
if ( c = = ' \" ' | | ! c )
2010-02-15 23:26:55 +00:00
{
com_token [ len ] = 0 ;
return data ;
}
com_token [ len ] = c ;
len + + ;
}
}
// parse single characters
2013-01-16 19:02:23 +00:00
if ( c = = ' { ' | | c = = ' } ' | | c = = ' ( ' | | c = = ' ) ' | | c = = ' \' ' | | c = = ' : ' )
2010-02-15 23:26:55 +00:00
{
com_token [ len ] = c ;
len + + ;
com_token [ len ] = 0 ;
return data + 1 ;
}
// parse a regular word
do
{
com_token [ len ] = c ;
data + + ;
len + + ;
c = * data ;
2010-03-06 13:35:05 +00:00
/* commented out the check for ':' so that ip:port works */
2013-01-16 19:02:23 +00:00
if ( c = = ' { ' | | c = = ' } ' | | c = = ' ( ' | | c = = ' ) ' | | c = = ' \' ' /* || c == ':' */ )
2010-02-15 23:26:55 +00:00
break ;
2011-12-28 23:40:27 +00:00
} while ( c > 32 ) ;
2010-02-15 23:26:55 +00:00
com_token [ len ] = 0 ;
return data ;
}
/*
= = = = = = = = = = = = = = = =
COM_CheckParm
Returns the position ( 1 to argc - 1 ) in the program ' s argument list
where the given parameter apears , or 0 if not present
= = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
int COM_CheckParmNext ( int last , const char * parm )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int i ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
for ( i = last + 1 ; i < com_argc ; i + + )
2010-02-15 23:26:55 +00:00
{
if ( ! com_argv [ i ] )
2011-12-28 23:40:27 +00:00
continue ; // NEXTSTEP sometimes clears appkit vars.
2010-02-15 23:26:55 +00:00
if ( ! Q_strcmp ( parm , com_argv [ i ] ) )
return i ;
}
return 0 ;
}
2017-09-17 02:12:53 +00:00
int COM_CheckParm ( const char * parm )
{
return COM_CheckParmNext ( 0 , parm ) ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = =
COM_CheckRegistered
Looks for the pop . txt file and verifies it .
Sets the " registered " cvar .
Immediately exits out if an alternate game was attempted to be started without
being registered .
= = = = = = = = = = = = = = = =
*/
2011-12-29 15:10:18 +00:00
static void COM_CheckRegistered ( void )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int h ;
unsigned short check [ 128 ] ;
int i ;
2010-02-15 23:26:55 +00:00
2011-01-02 21:45:16 +00:00
COM_OpenFile ( " gfx/pop.lmp " , & h , NULL ) ;
2010-02-15 23:26:55 +00:00
if ( h = = - 1 )
{
2012-04-20 19:47:22 +00:00
Cvar_SetROM ( " registered " , " 0 " ) ;
2010-02-15 23:26:55 +00:00
Con_Printf ( " Playing shareware version. \n " ) ;
if ( com_modified )
2017-08-14 04:10:32 +00:00
Sys_Error ( " You must have the registered version to use modified games. \n \n "
" Basedir is: %s \n \n "
" Check that this has an " GAMENAME " subdirectory containing pak0.pak and pak1.pak, "
" or use the -basedir command-line option to specify another directory. " ,
com_basedir ) ;
2010-02-15 23:26:55 +00:00
return ;
}
Sys_FileRead ( h , check , sizeof ( check ) ) ;
COM_CloseFile ( h ) ;
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < 128 ; i + + )
2011-12-29 15:10:18 +00:00
{
2010-02-15 23:26:55 +00:00
if ( pop [ i ] ! = ( unsigned short ) BigShort ( check [ i ] ) )
Sys_Error ( " Corrupted data file. " ) ;
2011-12-29 15:10:18 +00:00
}
for ( i = 0 ; com_cmdline [ i ] ; i + + )
{
if ( com_cmdline [ i ] ! = ' ' )
break ;
}
2010-02-15 23:26:55 +00:00
2011-12-29 15:10:18 +00:00
Cvar_SetROM ( " cmdline " , & com_cmdline [ i ] ) ;
2011-12-28 22:01:33 +00:00
Cvar_SetROM ( " registered " , " 1 " ) ;
2010-02-15 23:26:55 +00:00
Con_Printf ( " Playing registered version. \n " ) ;
}
/*
= = = = = = = = = = = = = = = =
COM_InitArgv
= = = = = = = = = = = = = = = =
*/
void COM_InitArgv ( int argc , char * * argv )
{
2011-12-28 23:40:27 +00:00
int i , j , n ;
2010-02-15 23:26:55 +00:00
// reconstitute the command line for the cmdline externally visible cvar
n = 0 ;
2011-12-28 23:40:27 +00:00
for ( j = 0 ; ( j < MAX_NUM_ARGVS ) & & ( j < argc ) ; j + + )
2010-02-15 23:26:55 +00:00
{
i = 0 ;
while ( ( n < ( CMDLINE_LENGTH - 1 ) ) & & argv [ j ] [ i ] )
{
com_cmdline [ n + + ] = argv [ j ] [ i + + ] ;
}
if ( n < ( CMDLINE_LENGTH - 1 ) )
com_cmdline [ n + + ] = ' ' ;
else
break ;
}
chase.c, cl_input.c, cl_parse.c, client.h, common.c, common.h, console.h,
cvar.h, draw.h, gl_draw.c, gl_fog.c, gl_mesh.c, gl_model.c, gl_model.h,
gl_rmain.c, gl_rmisc.c, gl_screen.c, gl_sky.c, gl_texmgr.c, glquake.h,
host.c, keys.c, keys.h, main.c, menu.c, menu.h, pr_cmds.c, quakedef.h,
r_alias.c, r_brush.c, r_part.c, r_sprite.c, r_world.c, sbar.c, sbar.h,
screen.h, snd_dma.c, snd_mem.c, snd_mix.c, sv_main.c, sys_sdl.c, vid.h,
view.h, world.c, world.h: Loads of warning fixes about missing function
prototypes, missing parens around &, missing braces leading to ambiguous
else statements and unused and uninitialized variables. There are still a
couple of unitialised variables here and there, but not much. The warnings
about strict aliasing violations need taking care of.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@21 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-02-16 12:01:07 +00:00
if ( n > 0 & & com_cmdline [ n - 1 ] = = ' ' )
2010-02-16 10:10:58 +00:00
com_cmdline [ n - 1 ] = 0 ; //johnfitz -- kill the trailing space
main_sdl.c (main): Remove leading linefeed from the init message.
common.c (COM_InitArgv): Move the leading linefeed to the end of message.
Index: main_sdl.c
===================================================================
--- main_sdl.c (revision 157)
+++ main_sdl.c (working copy)
@@ -58,7 +58,7 @@
if (!parms.membase)
Sys_Error ("Not enough memory free; check disk space\n");
- Con_Printf("\nFitzQuake %1.2f (c) John Fitzgibbons\n", FITZQUAKE_VERSION);
+ Con_Printf("FitzQuake %1.2f (c) John Fitzgibbons\n", FITZQUAKE_VERSION);
Con_Printf("SDL port (c) Sleepwalkr, Baker\n");
Con_Printf("QuakeSpasm %1.2f.%d (c) Ozkan Sezer, Stevenaaus\n", FITZQUAKE_VERSION, QUAKESPASM_VER_PATCH);
Index: common.c
===================================================================
--- common.c (revision 157)
+++ common.c (working copy)
@@ -1150,7 +1150,7 @@
if (n > 0 && com_cmdline[n-1] == ' ')
com_cmdline[n-1] = 0; //johnfitz -- kill the trailing space
- Con_Printf("\nCommand line: %s",com_cmdline);
+ Con_Printf("Command line: %s\n", com_cmdline);
safe = false;
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@158 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-04-27 07:15:19 +00:00
Con_Printf ( " Command line: %s \n " , com_cmdline ) ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
for ( com_argc = 0 ; ( com_argc < MAX_NUM_ARGVS ) & & ( com_argc < argc ) ; com_argc + + )
2010-02-15 23:26:55 +00:00
{
largv [ com_argc ] = argv [ com_argc ] ;
if ( ! Q_strcmp ( " -safe " , argv [ com_argc ] ) )
2010-08-29 12:55:41 +00:00
safemode = 1 ;
2010-02-15 23:26:55 +00:00
}
largv [ com_argc ] = argvdummy ;
com_argv = largv ;
if ( COM_CheckParm ( " -rogue " ) )
{
rogue = true ;
standard_quake = false ;
}
if ( COM_CheckParm ( " -hipnotic " ) | | COM_CheckParm ( " -quoth " ) ) //johnfitz -- "-quoth" support
{
hipnotic = true ;
standard_quake = false ;
}
}
/*
= = = = = = = = = = = = = = = =
Test_f - - johnfitz
= = = = = = = = = = = = = = = =
*/
# ifdef _DEBUG
2010-06-21 09:58:12 +00:00
static void FitzTest_f ( void )
2010-02-15 23:26:55 +00:00
{
}
# endif
2017-09-17 02:12:53 +00:00
entity_state_t nullentitystate ;
static void COM_SetupNullState ( void )
{
//the null state has some specific default values
// nullentitystate.drawflags = /*SCALE_ORIGIN_ORIGIN*/96;
nullentitystate . colormod [ 0 ] = 32 ;
nullentitystate . colormod [ 1 ] = 32 ;
nullentitystate . colormod [ 2 ] = 32 ;
// nullentitystate.glowmod[0] = 32;
// nullentitystate.glowmod[1] = 32;
// nullentitystate.glowmod[2] = 32;
nullentitystate . alpha = 0 ; //fte has 255 by default, with 0 for invisible. fitz uses 1 for invisible, 0 default, and 255=full alpha
nullentitystate . scale = 16 ;
// nullentitystate.solidsize = 0;//ES_SOLID_BSP;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = =
COM_Init
= = = = = = = = = = = = = = = =
*/
2011-04-19 16:41:45 +00:00
void COM_Init ( void )
2010-02-15 23:26:55 +00:00
{
2010-02-18 12:00:31 +00:00
int i = 0x12345678 ;
/* U N I X */
2010-02-15 23:26:55 +00:00
2010-02-18 12:00:31 +00:00
/*
BE_ORDER : 12 34 56 78
U N I X
LE_ORDER : 78 56 34 12
X I N U
PDP_ORDER : 34 12 78 56
N U X I
*/
if ( * ( char * ) & i = = 0x12 )
2011-06-12 12:25:22 +00:00
host_bigendian = true ;
2010-02-18 12:00:31 +00:00
else if ( * ( char * ) & i = = 0x78 )
2011-06-12 12:25:22 +00:00
host_bigendian = false ;
2010-02-18 12:00:31 +00:00
else /* if ( *(char *)&i == 0x34 ) */
Sys_Error ( " Unsupported endianism. " ) ;
2011-06-12 12:25:22 +00:00
if ( host_bigendian )
2010-02-15 23:26:55 +00:00
{
BigShort = ShortNoSwap ;
LittleShort = ShortSwap ;
BigLong = LongNoSwap ;
LittleLong = LongSwap ;
BigFloat = FloatNoSwap ;
LittleFloat = FloatSwap ;
}
2011-06-12 12:25:22 +00:00
else /* assumed LITTLE_ENDIAN. */
{
BigShort = ShortSwap ;
LittleShort = ShortNoSwap ;
BigLong = LongSwap ;
LittleLong = LongNoSwap ;
BigFloat = FloatSwap ;
LittleFloat = FloatNoSwap ;
}
2010-02-15 23:26:55 +00:00
2010-02-20 08:14:30 +00:00
if ( COM_CheckParm ( " -fitz " ) )
fitzmode = true ;
2010-02-15 23:26:55 +00:00
# ifdef _DEBUG
2010-06-21 09:58:12 +00:00
Cmd_AddCommand ( " fitztest " , FitzTest_f ) ; //johnfitz
2010-02-15 23:26:55 +00:00
# endif
2017-09-17 02:12:53 +00:00
COM_SetupNullState ( ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
va
2010-03-01 10:28:12 +00:00
does a varargs printf into a temp buffer . cycles between
4 different static buffers . the number of buffers cycled
is defined in VA_NUM_BUFFS .
2010-02-15 23:26:55 +00:00
FIXME : make this buffer size safe someday
= = = = = = = = = = = =
*/
2010-03-01 10:28:12 +00:00
# define VA_NUM_BUFFS 4
# define VA_BUFFERLEN 1024
static char * get_va_buffer ( void )
{
static char va_buffers [ VA_NUM_BUFFS ] [ VA_BUFFERLEN ] ;
static int buffer_idx = 0 ;
buffer_idx = ( buffer_idx + 1 ) & ( VA_NUM_BUFFS - 1 ) ;
return va_buffers [ buffer_idx ] ;
}
Constified Con_DebugLog, Con_Print, Con_Printf, Con_Warning, Con_DPrintf,
Con_DPrintf2, Con_SafePrintf, Con_CenterPrintf, Con_LogCenterPrint,
Con_NotifyBox, PL_ErrorDialog, PR_RunError, Host_EndGame, Host_Error,
SV_ClientPrintf, SV_BroadcastPrintf, Host_ClientCommands, Sys_DebugLog,
Sys_Error, Sys_Printf, BOPS_Error and va. Added noreturn attribute to
Sys_Error, Sys_Quit, BOPS_Error, PR_RunError, Host_EndGame and Host_Error.
Added format printf attribute to Con_DebugLog, Con_Printf, Con_Warning,
Con_DPrintf, Con_DPrintf2, Con_SafePrintf, Con_CenterPrintf, PL_ErrorDialog,
PR_RunError, Host_EndGame, Host_Error, SV_ClientPrintf, SV_BroadcastPrintf,
Host_ClientCommands, Sys_DebugLog, Sys_Error, Sys_Printf and va. Adjusted
Host_Status_f and NET_Ban_f for the new attributes. Fixed broken format
strings in Con_Dump_f, Mod_LoadTexinfo, PR_AllocStringSlots and FloorDivMod.
Defined __attribute__ macros in quakedef.h so that we don't break non-gcc
compilers.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@154 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-04-26 16:30:40 +00:00
char * va ( const char * format , . . . )
2010-02-15 23:26:55 +00:00
{
va_list argptr ;
2010-03-01 10:28:12 +00:00
char * va_buf ;
2010-02-15 23:26:55 +00:00
2010-03-01 10:28:12 +00:00
va_buf = get_va_buffer ( ) ;
2010-02-15 23:26:55 +00:00
va_start ( argptr , format ) ;
2010-08-31 16:57:12 +00:00
q_vsnprintf ( va_buf , VA_BUFFERLEN , format , argptr ) ;
2010-02-15 23:26:55 +00:00
va_end ( argptr ) ;
2010-03-01 10:28:12 +00:00
return va_buf ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
QUAKE FILESYSTEM
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-12-28 23:40:27 +00:00
int com_filesize ;
2010-02-15 23:26:55 +00:00
//
2014-09-08 21:10:33 +00:00
// on-disk pakfile
2010-02-15 23:26:55 +00:00
//
typedef struct
{
2011-12-28 23:40:27 +00:00
char name [ 56 ] ;
int filepos , filelen ;
2010-02-15 23:26:55 +00:00
} dpackfile_t ;
typedef struct
{
2011-12-28 23:40:27 +00:00
char id [ 4 ] ;
int dirofs ;
int dirlen ;
2010-02-15 23:26:55 +00:00
} dpackheader_t ;
2020-07-02 19:05:51 +00:00
# define MAX_FILES_IN_PACK 4096
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
char com_gamenames [ 1024 ] ; //eg: "hipnotic;quoth;warp", no id1, no private stuff
2011-12-28 23:40:27 +00:00
char com_gamedir [ MAX_OSPATH ] ;
char com_basedir [ MAX_OSPATH ] ;
int file_from_pak ; // ZOID: global indicating that file came from a pak
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
searchpath_t * com_searchpaths ;
2014-09-08 18:20:47 +00:00
searchpath_t * com_base_searchpaths ;
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = =
COM_Path_f
= = = = = = = = = = = =
*/
2011-12-29 15:10:18 +00:00
static void COM_Path_f ( void )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
searchpath_t * s ;
2010-02-15 23:26:55 +00:00
Con_Printf ( " Current search path: \n " ) ;
2011-12-28 23:40:27 +00:00
for ( s = com_searchpaths ; s ; s = s - > next )
2010-02-15 23:26:55 +00:00
{
if ( s - > pack )
{
Con_Printf ( " %s (%i files) \n " , s - > pack - > filename , s - > pack - > numfiles ) ;
}
else
Con_Printf ( " %s \n " , s - > filename ) ;
}
}
/*
= = = = = = = = = = = =
COM_WriteFile
The filename will be prefixed by the current game directory
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
void COM_WriteFile ( const char * filename , const void * data , int len )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int handle ;
char name [ MAX_OSPATH ] ;
2010-02-15 23:26:55 +00:00
Sys_mkdir ( com_gamedir ) ; //johnfitz -- if we've switched to a nonexistant gamedir, create it now so we don't crash
2011-12-27 10:50:42 +00:00
q_snprintf ( name , sizeof ( name ) , " %s/%s " , com_gamedir , filename ) ;
2010-02-15 23:26:55 +00:00
handle = Sys_FileOpenWrite ( name ) ;
if ( handle = = - 1 )
{
Sys_Printf ( " COM_WriteFile: failed on %s \n " , name ) ;
return ;
}
Sys_Printf ( " COM_WriteFile: %s \n " , name ) ;
Sys_FileWrite ( handle , data , len ) ;
Sys_FileClose ( handle ) ;
}
/*
= = = = = = = = = = = =
COM_CreatePath
= = = = = = = = = = = =
*/
2011-12-28 23:40:27 +00:00
void COM_CreatePath ( char * path )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
char * ofs ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
for ( ofs = path + 1 ; * ofs ; ofs + + )
2010-02-15 23:26:55 +00:00
{
if ( * ofs = = ' / ' )
2011-12-28 23:40:27 +00:00
{ // create the directory
2010-02-15 23:26:55 +00:00
* ofs = 0 ;
Sys_mkdir ( path ) ;
* ofs = ' / ' ;
}
}
}
2011-02-10 17:25:43 +00:00
/*
= = = = = = = = = = = = = = = =
COM_filelength
= = = = = = = = = = = = = = = =
*/
long COM_filelength ( FILE * f )
{
long pos , end ;
pos = ftell ( f ) ;
fseek ( f , 0 , SEEK_END ) ;
end = ftell ( f ) ;
fseek ( f , pos , SEEK_SET ) ;
return end ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = =
COM_FindFile
Finds the file in the search path .
Sets com_filesize and one of handle or file
2011-01-05 18:01:15 +00:00
If neither of file or handle is set , this
can be used for detecting a file ' s presence .
2010-02-15 23:26:55 +00:00
= = = = = = = = = = =
*/
2011-01-02 21:45:16 +00:00
static int COM_FindFile ( const char * filename , int * handle , FILE * * file ,
unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
searchpath_t * search ;
char netpath [ MAX_OSPATH ] ;
pack_t * pak ;
2012-02-12 11:33:07 +00:00
int i , findtime ;
2018-05-01 00:35:14 +00:00
const char * ext ;
2010-02-15 23:26:55 +00:00
if ( file & & handle )
Sys_Error ( " COM_FindFile: both handle and file set " ) ;
2010-12-30 16:35:16 +00:00
file_from_pak = 0 ;
2014-04-27 08:28:16 +00:00
2010-02-15 23:26:55 +00:00
//
// search through the path, one element at a time
//
2011-01-02 21:42:54 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
2010-02-15 23:26:55 +00:00
{
2011-02-10 17:25:43 +00:00
if ( search - > pack ) /* look through all the pak file elements */
2010-02-15 23:26:55 +00:00
{
pak = search - > pack ;
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < pak - > numfiles ; i + + )
2011-02-10 17:25:43 +00:00
{
if ( strcmp ( pak - > files [ i ] . name , filename ) ! = 0 )
continue ;
// found it!
com_filesize = pak - > files [ i ] . filelen ;
file_from_pak = 1 ;
if ( path_id )
* path_id = search - > path_id ;
if ( handle )
{
2017-09-17 02:12:53 +00:00
if ( pak - > files [ i ] . deflatedsize )
{
FILE * f ;
f = fopen ( pak - > filename , " rb " ) ;
if ( f )
{
fseek ( f , pak - > files [ i ] . filepos , SEEK_SET ) ;
f = FSZIP_Deflate ( f , pak - > files [ i ] . deflatedsize , pak - > files [ i ] . filelen ) ;
* handle = Sys_FileOpenStdio ( f ) ;
}
else
{ //error!
com_filesize = - 1 ;
* handle = - 1 ;
}
}
else
{
* handle = pak - > handle ;
Sys_FileSeek ( pak - > handle , pak - > files [ i ] . filepos ) ;
}
2011-02-10 17:25:43 +00:00
return com_filesize ;
}
else if ( file )
{ /* open a new file on the pakfile */
* file = fopen ( pak - > filename , " rb " ) ;
if ( * file )
2017-09-17 02:12:53 +00:00
{
2011-02-10 17:25:43 +00:00
fseek ( * file , pak - > files [ i ] . filepos , SEEK_SET ) ;
2017-09-17 02:12:53 +00:00
if ( pak - > files [ i ] . deflatedsize )
* file = FSZIP_Deflate ( * file , pak - > files [ i ] . deflatedsize , pak - > files [ i ] . filelen ) ;
}
2011-02-10 17:25:43 +00:00
return com_filesize ;
}
else /* for COM_FileExists() */
{
2010-02-15 23:26:55 +00:00
return com_filesize ;
}
2011-02-10 17:25:43 +00:00
}
2010-02-15 23:26:55 +00:00
}
2011-02-10 17:25:43 +00:00
else /* check a file in the directory tree */
2010-02-15 23:26:55 +00:00
{
2011-12-28 22:01:33 +00:00
if ( ! registered . value )
2011-02-10 17:25:43 +00:00
{ /* if not a registered version, don't ever go beyond base */
2010-02-15 23:26:55 +00:00
if ( strchr ( filename , ' / ' ) | | strchr ( filename , ' \\ ' ) )
continue ;
2017-09-17 02:12:53 +00:00
if ( q_strcasecmp ( COM_FileGetExtension ( filename ) , " dat " ) ) //don't load custom progs.dats either
continue ;
2010-02-15 23:26:55 +00:00
}
2011-12-27 10:50:42 +00:00
q_snprintf ( netpath , sizeof ( netpath ) , " %s/%s " , search - > filename , filename ) ;
2010-02-15 23:26:55 +00:00
findtime = Sys_FileTime ( netpath ) ;
if ( findtime = = - 1 )
continue ;
2011-01-02 21:45:16 +00:00
if ( path_id )
* path_id = search - > path_id ;
2010-02-15 23:26:55 +00:00
if ( handle )
2011-01-05 18:01:15 +00:00
{
2011-02-10 17:25:43 +00:00
com_filesize = Sys_FileOpenRead ( netpath , & i ) ;
2010-02-15 23:26:55 +00:00
* handle = i ;
2011-02-10 17:25:43 +00:00
return com_filesize ;
2011-01-05 18:01:15 +00:00
}
else if ( file )
2010-02-15 23:26:55 +00:00
{
* file = fopen ( netpath , " rb " ) ;
2011-02-10 17:25:43 +00:00
com_filesize = ( * file = = NULL ) ? - 1 : COM_filelength ( * file ) ;
return com_filesize ;
2010-02-15 23:26:55 +00:00
}
2011-01-05 18:01:15 +00:00
else
{
2011-02-10 17:25:43 +00:00
return 0 ; /* dummy valid value for COM_FileExists() */
2011-01-05 18:01:15 +00:00
}
2010-02-15 23:26:55 +00:00
}
}
2018-05-01 00:35:14 +00:00
ext = COM_FileGetExtension ( filename ) ;
if ( strcmp ( ext , " pcx " ) ! = 0
& & strcmp ( ext , " tga " ) ! = 0
& & strcmp ( ext , " png " ) ! = 0
& & strcmp ( ext , " jpg " ) ! = 0
& & strcmp ( ext , " jpeg " ) ! = 0
2020-07-22 01:37:16 +00:00
& & strcmp ( ext , " dds " ) ! = 0
2018-05-01 00:35:14 +00:00
& & strcmp ( ext , " lit " ) ! = 0
& & strcmp ( ext , " ent " ) ! = 0 )
2012-02-12 11:33:07 +00:00
Con_DPrintf ( " FindFile: can't find %s \n " , filename ) ;
else Con_DPrintf2 ( " FindFile: can't find %s \n " , filename ) ;
2015-05-25 18:38:37 +00:00
// Log pcx, tga, lit, ent misses only if (developer.value >= 2)
2012-02-12 02:59:21 +00:00
2010-02-15 23:26:55 +00:00
if ( handle )
* handle = - 1 ;
2011-02-10 17:25:43 +00:00
if ( file )
2010-02-15 23:26:55 +00:00
* file = NULL ;
com_filesize = - 1 ;
2011-02-10 17:25:43 +00:00
return com_filesize ;
2010-02-15 23:26:55 +00:00
}
2011-01-05 18:01:15 +00:00
/*
= = = = = = = = = = =
COM_FileExists
2011-02-10 17:25:43 +00:00
Returns whether the file is found in the quake filesystem .
2011-01-05 18:01:15 +00:00
= = = = = = = = = = =
*/
2011-02-10 17:25:43 +00:00
qboolean COM_FileExists ( const char * filename , unsigned int * path_id )
2011-01-05 18:01:15 +00:00
{
2011-02-10 17:25:43 +00:00
int ret = COM_FindFile ( filename , NULL , NULL , path_id ) ;
return ( ret = = - 1 ) ? false : true ;
2011-01-05 18:01:15 +00:00
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = =
COM_OpenFile
filename never has a leading slash , but may contain directory walks
returns a handle and a length
it may actually be inside a pak file
= = = = = = = = = = =
*/
2011-01-02 21:45:16 +00:00
int COM_OpenFile ( const char * filename , int * handle , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_FindFile ( filename , handle , NULL , path_id ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = =
COM_FOpenFile
If the requested file is inside a packfile , a new FILE * will be opened
into the file .
= = = = = = = = = = =
*/
2011-01-02 21:45:16 +00:00
int COM_FOpenFile ( const char * filename , FILE * * file , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_FindFile ( filename , NULL , file , path_id ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
COM_CloseFile
If it is a pak file handle , don ' t really close it
= = = = = = = = = = = =
*/
void COM_CloseFile ( int h )
{
2011-12-28 23:40:27 +00:00
searchpath_t * s ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
for ( s = com_searchpaths ; s ; s = s - > next )
2010-02-15 23:26:55 +00:00
if ( s - > pack & & s - > pack - > handle = = h )
return ;
Sys_FileClose ( h ) ;
}
/*
= = = = = = = = = = = =
COM_LoadFile
Filename are reletive to the quake directory .
Allways appends a 0 byte .
= = = = = = = = = = = =
*/
2010-12-31 10:29:38 +00:00
# define LOADFILE_ZONE 0
# define LOADFILE_HUNK 1
# define LOADFILE_TEMPHUNK 2
# define LOADFILE_CACHE 3
# define LOADFILE_STACK 4
2011-08-03 19:22:29 +00:00
# define LOADFILE_MALLOC 5
2010-12-31 10:29:38 +00:00
static byte * loadbuf ;
static cache_user_t * loadcache ;
static int loadsize ;
2011-01-02 21:45:16 +00:00
byte * COM_LoadFile ( const char * path , int usehunk , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
int h ;
byte * buf ;
char base [ 32 ] ;
int len ;
2010-02-15 23:26:55 +00:00
2011-12-28 23:40:27 +00:00
buf = NULL ; // quiet compiler warning
2010-02-15 23:26:55 +00:00
// look for it in the filesystem or pack files
2011-01-02 21:45:16 +00:00
len = COM_OpenFile ( path , & h , path_id ) ;
2010-02-15 23:26:55 +00:00
if ( h = = - 1 )
return NULL ;
// extract the filename base name for hunk tag
2011-12-27 08:04:02 +00:00
COM_FileBase ( path , base , sizeof ( base ) ) ;
2010-02-15 23:26:55 +00:00
2010-12-31 10:29:38 +00:00
switch ( usehunk )
{
case LOADFILE_HUNK :
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) Hunk_AllocName ( len + 1 , base ) ;
2010-12-31 10:29:38 +00:00
break ;
case LOADFILE_TEMPHUNK :
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) Hunk_TempAlloc ( len + 1 ) ;
2010-12-31 10:29:38 +00:00
break ;
case LOADFILE_ZONE :
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) Z_Malloc ( len + 1 ) ;
2010-12-31 10:29:38 +00:00
break ;
case LOADFILE_CACHE :
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
buf = ( byte * ) Cache_Alloc ( loadcache , len + 1 , base ) ;
2010-12-31 10:29:38 +00:00
break ;
case LOADFILE_STACK :
if ( len < loadsize )
buf = loadbuf ;
2010-02-15 23:26:55 +00:00
else
2010-12-31 10:29:38 +00:00
buf = ( byte * ) Hunk_TempAlloc ( len + 1 ) ;
break ;
case LOADFILE_MALLOC :
buf = ( byte * ) malloc ( len + 1 ) ;
break ;
default :
2010-02-15 23:26:55 +00:00
Sys_Error ( " COM_LoadFile: bad usehunk " ) ;
2010-12-31 10:29:38 +00:00
}
2010-02-15 23:26:55 +00:00
if ( ! buf )
Sys_Error ( " COM_LoadFile: not enough space for %s " , path ) ;
( ( byte * ) buf ) [ len ] = 0 ;
Sys_FileRead ( h , buf , len ) ;
COM_CloseFile ( h ) ;
return buf ;
}
2011-01-02 21:45:16 +00:00
byte * COM_LoadHunkFile ( const char * path , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_LoadFile ( path , LOADFILE_HUNK , path_id ) ;
2010-12-31 10:29:38 +00:00
}
2011-01-02 21:45:16 +00:00
byte * COM_LoadZoneFile ( const char * path , unsigned int * path_id )
2010-12-31 10:29:38 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_LoadFile ( path , LOADFILE_ZONE , path_id ) ;
2010-02-15 23:26:55 +00:00
}
2011-01-02 21:45:16 +00:00
byte * COM_LoadTempFile ( const char * path , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_LoadFile ( path , LOADFILE_TEMPHUNK , path_id ) ;
2010-02-15 23:26:55 +00:00
}
2011-01-02 21:45:16 +00:00
void COM_LoadCacheFile ( const char * path , struct cache_user_s * cu , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
loadcache = cu ;
2011-01-02 21:45:16 +00:00
COM_LoadFile ( path , LOADFILE_CACHE , path_id ) ;
2010-02-15 23:26:55 +00:00
}
// uses temp hunk if larger than bufsize
2011-01-02 21:45:16 +00:00
byte * COM_LoadStackFile ( const char * path , void * buffer , int bufsize , unsigned int * path_id )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
byte * buf ;
2010-02-15 23:26:55 +00:00
loadbuf = ( byte * ) buffer ;
loadsize = bufsize ;
2011-01-02 21:45:16 +00:00
buf = COM_LoadFile ( path , LOADFILE_STACK , path_id ) ;
2010-12-31 10:29:38 +00:00
return buf ;
}
// returns malloc'd memory
2011-01-02 21:45:16 +00:00
byte * COM_LoadMallocFile ( const char * path , unsigned int * path_id )
2010-12-31 10:29:38 +00:00
{
2011-01-02 21:45:16 +00:00
return COM_LoadFile ( path , LOADFILE_MALLOC , path_id ) ;
2010-12-31 10:29:38 +00:00
}
2017-05-09 00:01:41 +00:00
byte * COM_LoadMallocFile_TextMode_OSPath ( const char * path , long * len_out )
2017-04-16 02:53:06 +00:00
{
FILE * f ;
byte * data ;
2017-05-09 00:01:41 +00:00
long len , actuallen ;
2017-04-16 02:53:06 +00:00
2017-05-09 00:01:41 +00:00
// ericw -- this is used by Host_Loadgame_f. Translate CRLF to LF on load games,
// othewise multiline messages have a garbage character at the end of each line.
// TODO: could handle in a way that allows loading CRLF savegames on mac/linux
// without the junk characters appearing.
f = fopen ( path , " rt " ) ;
2017-04-16 02:53:06 +00:00
if ( f = = NULL )
return NULL ;
len = COM_filelength ( f ) ;
if ( len < 0 )
return NULL ;
data = ( byte * ) malloc ( len + 1 ) ;
if ( data = = NULL )
return NULL ;
2017-05-09 00:01:41 +00:00
// (actuallen < len) if CRLF to LF translation was performed
actuallen = fread ( data , 1 , len , f ) ;
if ( ferror ( f ) )
2017-04-16 02:53:06 +00:00
{
free ( data ) ;
return NULL ;
}
2017-05-09 00:01:41 +00:00
data [ actuallen ] = ' \0 ' ;
2017-04-16 02:53:06 +00:00
if ( len_out ! = NULL )
2017-05-09 00:01:41 +00:00
* len_out = actuallen ;
2017-04-16 02:53:06 +00:00
return data ;
}
const char * COM_ParseIntNewline ( const char * buffer , int * value )
{
int consumed = 0 ;
sscanf ( buffer , " %i \n %n " , value , & consumed ) ;
return buffer + consumed ;
}
const char * COM_ParseFloatNewline ( const char * buffer , float * value )
{
int consumed = 0 ;
sscanf ( buffer , " %f \n %n " , value , & consumed ) ;
return buffer + consumed ;
}
const char * COM_ParseStringNewline ( const char * buffer )
{
int consumed = 0 ;
com_token [ 0 ] = ' \0 ' ;
sscanf ( buffer , " %1023s \n %n " , com_token , & consumed ) ;
return buffer + consumed ;
}
2010-12-31 10:29:38 +00:00
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = =
COM_LoadPackFile - - johnfitz - - modified based on topaz ' s tutorial
Takes an explicit ( not game tree related ) path to a pak file .
Loads the header and directory , adding the files at the beginning
of the list so they override previous pack files .
= = = = = = = = = = = = = = = = =
*/
2014-09-08 21:10:33 +00:00
static pack_t * COM_LoadPackFile ( const char * packfile )
2010-02-15 23:26:55 +00:00
{
2011-12-28 23:40:27 +00:00
dpackheader_t header ;
int i ;
packfile_t * newfiles ;
int numpackfiles ;
pack_t * pack ;
int packhandle ;
dpackfile_t info [ MAX_FILES_IN_PACK ] ;
unsigned short crc ;
2010-02-15 23:26:55 +00:00
if ( Sys_FileOpenRead ( packfile , & packhandle ) = = - 1 )
return NULL ;
2015-02-08 08:00:56 +00:00
2010-02-15 23:26:55 +00:00
Sys_FileRead ( packhandle , ( void * ) & header , sizeof ( header ) ) ;
if ( header . id [ 0 ] ! = ' P ' | | header . id [ 1 ] ! = ' A ' | | header . id [ 2 ] ! = ' C ' | | header . id [ 3 ] ! = ' K ' )
Sys_Error ( " %s is not a packfile " , packfile ) ;
2015-02-08 08:00:56 +00:00
2010-02-15 23:26:55 +00:00
header . dirofs = LittleLong ( header . dirofs ) ;
header . dirlen = LittleLong ( header . dirlen ) ;
numpackfiles = header . dirlen / sizeof ( dpackfile_t ) ;
2015-02-08 08:00:56 +00:00
if ( header . dirlen < 0 | | header . dirofs < 0 )
{
Sys_Error ( " Invalid packfile %s (dirlen: %i, dirofs: %i) " ,
packfile , header . dirlen , header . dirofs ) ;
}
if ( ! numpackfiles )
{
Sys_Printf ( " WARNING: %s has no files, ignored \n " , packfile ) ;
Sys_FileClose ( packhandle ) ;
return NULL ;
}
2010-02-15 23:26:55 +00:00
if ( numpackfiles > MAX_FILES_IN_PACK )
Sys_Error ( " %s has %i files " , packfile , numpackfiles ) ;
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
newfiles = ( packfile_t * ) Z_Malloc ( numpackfiles * sizeof ( packfile_t ) ) ;
2010-02-15 23:26:55 +00:00
Sys_FileSeek ( packhandle , header . dirofs ) ;
Sys_FileRead ( packhandle , ( void * ) info , header . dirlen ) ;
2017-09-17 02:12:53 +00:00
if ( numpackfiles ! = PAK0_COUNT )
com_modified = true ; // not the original file
else
{
// crc the directory to check for modifications
CRC_Init ( & crc ) ;
for ( i = 0 ; i < header . dirlen ; i + + )
CRC_ProcessByte ( & crc , ( ( byte * ) info ) [ i ] ) ;
if ( crc ! = PAK0_CRC_V106 & & crc ! = PAK0_CRC_V101 & & crc ! = PAK0_CRC_V100 )
com_modified = true ;
}
2010-02-15 23:26:55 +00:00
// parse the directory
2011-12-28 23:40:27 +00:00
for ( i = 0 ; i < numpackfiles ; i + + )
2010-02-15 23:26:55 +00:00
{
2011-12-27 13:15:31 +00:00
q_strlcpy ( newfiles [ i ] . name , info [ i ] . name , sizeof ( newfiles [ i ] . name ) ) ;
2010-02-15 23:26:55 +00:00
newfiles [ i ] . filepos = LittleLong ( info [ i ] . filepos ) ;
newfiles [ i ] . filelen = LittleLong ( info [ i ] . filelen ) ;
}
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
pack = ( pack_t * ) Z_Malloc ( sizeof ( pack_t ) ) ;
2011-12-27 13:15:31 +00:00
q_strlcpy ( pack - > filename , packfile , sizeof ( pack - > filename ) ) ;
2010-02-15 23:26:55 +00:00
pack - > handle = packhandle ;
pack - > numfiles = numpackfiles ;
pack - > files = newfiles ;
2015-02-08 08:00:56 +00:00
//Sys_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
2010-02-15 23:26:55 +00:00
return pack ;
}
2018-05-01 00:35:14 +00:00
# ifdef _WIN32
static time_t Sys_FileTimeToTime ( FILETIME ft )
{
ULARGE_INTEGER ull ;
ull . LowPart = ft . dwLowDateTime ;
ull . HighPart = ft . dwHighDateTime ;
return ull . QuadPart / 10000000u - 11644473600u ;
}
# endif
2017-09-17 02:12:53 +00:00
2018-05-01 00:35:14 +00:00
void COM_ListSystemFiles ( void * ctx , const char * gamedir , const char * ext , qboolean ( * cb ) ( void * ctx , const char * fname ) )
2017-09-17 02:12:53 +00:00
{
# ifdef _WIN32
WIN32_FIND_DATA fdat ;
HANDLE fhnd ;
char filestring [ MAX_OSPATH ] ;
q_snprintf ( filestring , sizeof ( filestring ) , " %s/*.%s " , gamedir , ext ) ;
fhnd = FindFirstFile ( filestring , & fdat ) ;
if ( fhnd = = INVALID_HANDLE_VALUE )
return ;
do
{
cb ( ctx , fdat . cFileName ) ;
} while ( FindNextFile ( fhnd , & fdat ) ) ;
FindClose ( fhnd ) ;
# else
DIR * dir_p ;
struct dirent * dir_t ;
dir_p = opendir ( gamedir ) ;
if ( dir_p = = NULL )
return ;
while ( ( dir_t = readdir ( dir_p ) ) ! = NULL )
{
if ( q_strcasecmp ( COM_FileGetExtension ( dir_t - > d_name ) , ext ) ! = 0 )
continue ;
cb ( ctx , dir_t - > d_name ) ;
}
closedir ( dir_p ) ;
# endif
}
2020-07-19 00:36:32 +00:00
static void COM_ListFiles ( void * ctx , searchpath_t * spath , const char * pattern , qboolean ( * cb ) ( void * ctx , const char * fname , time_t mtime , size_t fsize , searchpath_t * spath ) )
2018-05-01 00:35:14 +00:00
{
char prefixdir [ MAX_OSPATH ] ;
char * sl ;
sl = strrchr ( pattern , ' / ' ) ;
if ( sl )
{
sl + + ;
if ( sl - pattern > = MAX_OSPATH )
return ;
memcpy ( prefixdir , pattern , sl - pattern ) ;
prefixdir [ sl - pattern ] = 0 ;
pattern = sl ;
}
else
* prefixdir = 0 ;
# ifdef _WIN32
{
char filestring [ MAX_OSPATH ] ;
WIN32_FIND_DATA fdat ;
HANDLE fhnd ;
2020-07-19 00:36:32 +00:00
q_snprintf ( filestring , sizeof ( filestring ) , " %s/%s%s " , spath - > filename , prefixdir , pattern ) ;
2018-05-01 00:35:14 +00:00
fhnd = FindFirstFile ( filestring , & fdat ) ;
if ( fhnd = = INVALID_HANDLE_VALUE )
return ;
do
{
q_snprintf ( filestring , sizeof ( filestring ) , " %s%s " , prefixdir , fdat . cFileName ) ;
2020-07-19 00:36:32 +00:00
cb ( ctx , filestring , Sys_FileTimeToTime ( fdat . ftLastWriteTime ) , fdat . nFileSizeLow , spath ) ;
2018-05-01 00:35:14 +00:00
} while ( FindNextFile ( fhnd , & fdat ) ) ;
FindClose ( fhnd ) ;
}
# else
{
char filestring [ MAX_OSPATH ] ;
DIR * dir_p ;
struct dirent * dir_t ;
2020-07-19 00:36:32 +00:00
q_snprintf ( filestring , sizeof ( filestring ) , " %s/%s " , spath - > filename , prefixdir ) ;
2018-05-01 00:35:14 +00:00
dir_p = opendir ( filestring ) ;
if ( dir_p = = NULL )
return ;
while ( ( dir_t = readdir ( dir_p ) ) ! = NULL )
{
2020-07-19 00:36:32 +00:00
if ( * dir_t - > d_name = = ' . ' ) //ignore hidden paths... and parent etc weirdness.
continue ;
2018-05-01 00:35:14 +00:00
if ( ! fnmatch ( pattern , dir_t - > d_name , FNM_NOESCAPE | FNM_PATHNAME | FNM_CASEFOLD ) )
{
2020-07-19 00:36:32 +00:00
struct stat s ;
q_snprintf ( filestring , sizeof ( filestring ) , " %s/%s%s " , spath - > filename , prefixdir , dir_t - > d_name ) ;
if ( stat ( filestring , & s ) < 0 )
memset ( & s , 0 , sizeof ( s ) ) ;
2018-05-01 00:35:14 +00:00
q_snprintf ( filestring , sizeof ( filestring ) , " %s%s " , prefixdir , dir_t - > d_name ) ;
2020-07-19 00:36:32 +00:00
cb ( ctx , filestring , s . st_mtime , s . st_size , spath ) ;
2018-05-01 00:35:14 +00:00
}
}
closedir ( dir_p ) ;
}
# endif
}
2020-09-04 12:17:28 +00:00
void COM_ListAllFiles ( void * ctx , const char * pattern , qboolean ( * cb ) ( void * ctx , const char * fname , time_t mtime , size_t fsize , searchpath_t * spath ) , unsigned int flags , const char * pkgfilter )
2020-07-19 00:36:32 +00:00
{
searchpath_t * search ;
2020-09-04 12:17:28 +00:00
const char * sp ;
qboolean foundpackage = false ;
2020-07-19 00:36:32 +00:00
if ( * pattern = = ' / ' | | strchr ( pattern , ' : ' ) //block absolute paths
| | strchr ( pattern , ' \\ ' ) //block unportable paths (also ones that mess up other checks)
| | strstr ( pattern , " ./ " ) ) //block evil relative paths (any kind)
{
Con_Printf ( " Blocking absolute/non-portable/dodgy search pattern: %s \n " , pattern ) ;
return ;
}
//don't add the same pak twice.
for ( search = com_searchpaths ; search ; search = search - > next )
{
2020-09-04 12:17:28 +00:00
if ( pkgfilter )
{
if ( flags & ( 1u < < 1 ) )
sp = search - > purename ;
else
{
sp = strchr ( search - > purename , ' / ' ) ;
if ( sp & & ! strchr ( + + sp , ' / ' ) )
;
else
continue ; //ignore packages inside other packages. they're just too weird.
}
if ( strcmp ( pkgfilter , sp ) )
continue ; //ignore this package
}
foundpackage = true ;
2020-07-19 00:36:32 +00:00
if ( search - > pack )
{
pack_t * pak = search - > pack ;
int i ;
for ( i = 0 ; i < pak - > numfiles ; i + + )
{
if ( wildcmp ( pattern , pak - > files [ i ] . name ) )
cb ( ctx , pak - > files [ i ] . name , pak - > mtime , pak - > files [ i ] . filelen , search ) ;
}
}
else
{
COM_ListFiles ( ctx , search , pattern , cb ) ;
}
}
2020-09-04 12:17:28 +00:00
if ( flags & ( 1u < < 1 ) & & ( flags & ( 1u < < 2 ) ) & & pkgfilter & & foundpackage )
{ //if we're using full package paths, and we're trying to force the search, then be prepared to search gamedirs which are not currently active too if we didn't already search it.
// searchpath_t dummy;
// dummy.filename =
Con_Printf ( " search_begin: SB_FORCESEARCH not supported \n " ) ;
}
2020-07-19 00:36:32 +00:00
}
2017-09-17 02:12:53 +00:00
2020-09-04 12:17:28 +00:00
static qboolean COM_AddPackage ( searchpath_t * basepath , const char * pakfile , const char * purename )
2017-09-17 02:12:53 +00:00
{
searchpath_t * search ;
pack_t * pak ;
const char * ext = COM_FileGetExtension ( pakfile ) ;
//don't add the same pak twice.
for ( search = com_searchpaths ; search ; search = search - > next )
{
if ( search - > pack )
if ( ! q_strcasecmp ( pakfile , search - > pack - > filename ) )
return true ;
}
if ( ! q_strcasecmp ( ext , " pak " ) )
pak = COM_LoadPackFile ( pakfile ) ;
else if ( ! q_strcasecmp ( ext , " pk3 " ) | | ! q_strcasecmp ( ext , " pk4 " ) | | ! q_strcasecmp ( ext , " zip " ) | | ! q_strcasecmp ( ext , " apk " ) )
{
pak = FSZIP_LoadArchive ( pakfile ) ;
if ( pak )
com_modified = true ; //would always be true, so we don't bother with crcs.
}
else
pak = NULL ;
if ( ! pak )
return false ;
2020-07-19 00:36:32 +00:00
{
struct stat s ;
if ( stat ( pakfile , & s ) > = 0 )
pak - > mtime = s . st_mtime ;
}
2017-09-17 02:12:53 +00:00
search = ( searchpath_t * ) Z_Malloc ( sizeof ( searchpath_t ) ) ;
2020-09-04 12:17:28 +00:00
q_strlcpy ( search - > filename , pakfile , sizeof ( search - > filename ) ) ;
q_strlcpy ( search - > purename , purename , sizeof ( search - > purename ) ) ;
2017-09-17 02:12:53 +00:00
search - > path_id = basepath - > path_id ;
search - > pack = pak ;
search - > next = com_searchpaths ;
com_searchpaths = search ;
return true ;
}
static qboolean COM_AddEnumeratedPackage ( void * ctx , const char * pakfile )
{
searchpath_t * basepath = ctx ;
char fullpakfile [ MAX_OSPATH ] ;
2020-09-04 12:17:28 +00:00
char purepakfile [ MAX_OSPATH ] ;
2017-09-17 02:12:53 +00:00
q_snprintf ( fullpakfile , sizeof ( fullpakfile ) , " %s/%s " , basepath - > filename , pakfile ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purepakfile , sizeof ( purepakfile ) , " %s/%s " , basepath - > purename , pakfile ) ;
return COM_AddPackage ( basepath , fullpakfile , purepakfile ) ;
2017-09-17 02:12:53 +00:00
}
const char * COM_GetGameNames ( qboolean full )
{
if ( full )
{
if ( * com_gamenames )
return va ( " %s;%s " , GAMENAME , com_gamenames ) ;
else
return GAMENAME ;
}
return com_gamenames ;
// return COM_SkipPath(com_gamedir);
}
//if either contain id1 then that gets ignored
qboolean COM_GameDirMatches ( const char * tdirs )
{
int gnl = strlen ( GAMENAME ) ;
const char * odirs = COM_GetGameNames ( false ) ;
//ignore any core paths.
if ( ! strncmp ( tdirs , GAMENAME , gnl ) & & ( tdirs [ gnl ] = = ' ; ' | | ! tdirs [ gnl ] ) )
{
tdirs + = gnl ;
if ( * tdirs = = ' ; ' )
tdirs + + ;
}
if ( ! strncmp ( odirs , GAMENAME , gnl ) & & ( odirs [ gnl ] = = ' ; ' | | ! odirs [ gnl ] ) )
{
odirs + = gnl ;
if ( * odirs = = ' ; ' )
odirs + + ;
}
//skip any qw in there from quakeworld (remote servers should really be skipping this, unless its maybe the only one in the path).
if ( ! strncmp ( tdirs , " qw; " , 3 ) | | ! strcmp ( tdirs , " qw " ) )
{
tdirs + = 2 ;
if ( * tdirs = = ' ; ' )
tdirs + + ;
}
if ( ! strncmp ( odirs , " qw; " , 3 ) | | ! strcmp ( odirs , " qw " ) ) //need to cope with ourselves setting it that way too, just in case.
{
odirs + = 2 ;
if ( * odirs = = ' ; ' )
odirs + + ;
}
//okay, now check it properly
if ( ! strcmp ( odirs , tdirs ) )
return true ;
return false ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = =
COM_AddGameDirectory - - johnfitz - - modified based on topaz ' s tutorial
= = = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
static void COM_AddGameDirectory ( const char * dir )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
const char * base = com_basedir ;
2010-02-15 23:26:55 +00:00
int i ;
2011-01-02 21:45:16 +00:00
unsigned int path_id ;
2017-09-17 02:12:53 +00:00
searchpath_t * searchdir ;
2010-02-15 23:26:55 +00:00
char pakfile [ MAX_OSPATH ] ;
2020-09-04 12:17:28 +00:00
char purename [ MAX_OSPATH ] ;
2014-09-10 07:28:28 +00:00
qboolean been_here = false ;
2017-09-17 02:12:53 +00:00
FILE * listing ;
qboolean found ;
const char * enginepackname = " quakespasm " ;
if ( * dir = = ' * ' )
dir + + ;
else if ( ! strchr ( dir , ' / ' ) & & ! strchr ( dir , ' \\ ' ) )
{
//fixme: block dupes
if ( * com_gamenames )
q_strlcat ( com_gamenames , " ; " , sizeof ( com_gamenames ) ) ;
q_strlcat ( com_gamenames , dir , sizeof ( com_gamenames ) ) ;
}
//quakespasm enables mission pack flags automatically, so -game rogue works without breaking the hud
//we might as well do that here to simplify the code.
if ( ! q_strcasecmp ( dir , " rogue " ) ) {
rogue = true ;
standard_quake = false ;
}
if ( ! q_strcasecmp ( dir , " hipnotic " ) | | ! q_strcasecmp ( dir , " quoth " ) ) {
hipnotic = true ;
standard_quake = false ;
}
2010-02-15 23:26:55 +00:00
2014-04-27 08:28:16 +00:00
q_strlcpy ( com_gamedir , va ( " %s/%s " , base , dir ) , sizeof ( com_gamedir ) ) ;
2010-02-15 23:26:55 +00:00
2011-01-02 21:45:16 +00:00
// assign a path_id to this game directory
if ( com_searchpaths )
path_id = com_searchpaths - > path_id < < 1 ;
else path_id = 1U ;
2014-09-10 07:28:28 +00:00
_add_path :
2017-09-17 02:12:53 +00:00
searchdir = ( searchpath_t * ) Z_Malloc ( sizeof ( searchpath_t ) ) ;
searchdir - > path_id = path_id ;
q_strlcpy ( searchdir - > filename , com_gamedir , sizeof ( searchdir - > filename ) ) ;
2020-09-04 12:17:28 +00:00
q_strlcpy ( searchdir - > purename , dir , sizeof ( searchdir - > purename ) ) ;
2017-09-17 02:12:53 +00:00
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/pak.lst " , com_gamedir ) ;
listing = fopen ( pakfile , " rb " ) ;
if ( listing )
{
int len ;
char * buffer ;
const char * name ;
fseek ( listing , 0 , SEEK_END ) ;
len = ftell ( listing ) ;
fseek ( listing , 0 , SEEK_SET ) ;
buffer = Z_Malloc ( len + 1 ) ;
fread ( buffer , 1 , len , listing ) ;
buffer [ len ] = 0 ;
fclose ( listing ) ;
name = buffer ;
com_modified = true ; //any reordering of paks should be frowned upon
while ( ( name = COM_Parse ( name ) ) )
{
if ( ! * com_token )
continue ;
if ( strchr ( com_token , ' / ' ) | | strchr ( com_token , ' \\ ' ) | | strchr ( com_token , ' : ' ) )
continue ;
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/%s " , com_gamedir , com_token ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s/%s " , dir , com_token ) ;
COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
if ( path_id = = 1 & & ! fitzmode & & ! q_strncasecmp ( com_token , " pak0. " , 5 ) )
{ //add this now, to try to retain correct ordering.
qboolean old = com_modified ;
if ( been_here ) base = host_parms - > userdir ;
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/%s.%s " , base , enginepackname , COM_FileGetExtension ( com_token ) ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s.%s " , enginepackname , COM_FileGetExtension ( com_token ) ) ;
COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
com_modified = old ;
}
}
}
2014-09-08 09:10:27 +00:00
2010-02-15 23:26:55 +00:00
// add any pak files in the format pak0.pak pak1.pak, ...
for ( i = 0 ; ; i + + )
{
2017-09-17 02:12:53 +00:00
found = false ;
2014-04-27 08:28:16 +00:00
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/pak%i.pak " , com_gamedir , i ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s/pak%i.pak " , dir , i ) ;
found | = COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/pak%i.pk3 " , com_gamedir , i ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s/pak%i.pk3 " , dir , i ) ;
found | = COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
if ( i = = 0 & & path_id = = 1 & & ! fitzmode )
{
2014-04-27 08:28:16 +00:00
qboolean old = com_modified ;
2014-09-10 07:28:28 +00:00
if ( been_here ) base = host_parms - > userdir ;
2017-09-17 02:12:53 +00:00
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/%s.pak " , base , enginepackname ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s.pak " , enginepackname ) ;
COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
q_snprintf ( pakfile , sizeof ( pakfile ) , " %s/%s.pk3 " , base , enginepackname ) ;
2020-09-04 12:17:28 +00:00
q_snprintf ( purename , sizeof ( purename ) , " %s.pk3 " , enginepackname ) ;
COM_AddPackage ( searchdir , pakfile , purename ) ;
2017-09-17 02:12:53 +00:00
2014-04-28 05:40:28 +00:00
com_modified = old ;
2010-02-20 08:50:31 +00:00
}
2017-09-17 02:12:53 +00:00
if ( ! found )
break ;
2010-02-20 08:50:31 +00:00
}
2014-09-10 07:28:28 +00:00
2017-09-17 02:12:53 +00:00
i = COM_CheckParm ( " -nowildpaks " ) ;
if ( ! i )
{
COM_ListSystemFiles ( searchdir , com_gamedir , " pak " , COM_AddEnumeratedPackage ) ;
COM_ListSystemFiles ( searchdir , com_gamedir , " pk3 " , COM_AddEnumeratedPackage ) ;
}
// then finally link the directory to the search path
//spike -- moved this last (also explicitly blocked loading progs.dat from system paths when running the demo)
searchdir - > next = com_searchpaths ;
com_searchpaths = searchdir ;
2014-09-10 07:28:28 +00:00
if ( ! been_here & & host_parms - > userdir ! = host_parms - > basedir )
{
been_here = true ;
q_strlcpy ( com_gamedir , va ( " %s/%s " , host_parms - > userdir , dir ) , sizeof ( com_gamedir ) ) ;
Sys_mkdir ( com_gamedir ) ;
goto _add_path ;
}
2010-02-20 08:50:31 +00:00
}
2017-09-17 02:12:53 +00:00
void COM_ResetGameDirectories ( char * newgamedirs )
{
char * newpath , * path ;
searchpath_t * search ;
//Kill the extra game if it is loaded
while ( com_searchpaths ! = com_base_searchpaths )
{
if ( com_searchpaths - > pack )
{
Sys_FileClose ( com_searchpaths - > pack - > handle ) ;
Z_Free ( com_searchpaths - > pack - > files ) ;
Z_Free ( com_searchpaths - > pack ) ;
}
search = com_searchpaths - > next ;
Z_Free ( com_searchpaths ) ;
com_searchpaths = search ;
}
hipnotic = false ;
rogue = false ;
standard_quake = true ;
//wipe the list of mod gamedirs
* com_gamenames = 0 ;
//reset this too
q_strlcpy ( com_gamedir , va ( " %s/%s " , ( host_parms - > userdir ! = host_parms - > basedir ) ? host_parms - > userdir : com_basedir , GAMENAME ) , sizeof ( com_gamedir ) ) ;
for ( newpath = newgamedirs ; newpath & & * newpath ; )
{
char * e = strchr ( newpath , ' ; ' ) ;
if ( e )
* e + + = 0 ;
if ( ! q_strcasecmp ( GAMENAME , newpath ) )
path = NULL ;
else for ( path = newgamedirs ; path < newpath ; path + = strlen ( path ) + 1 )
{
if ( ! q_strcasecmp ( path , newpath ) )
break ;
}
if ( path = = newpath ) //not already loaded
COM_AddGameDirectory ( newpath ) ;
newpath = e ;
}
}
2014-09-08 21:10:33 +00:00
//==============================================================================
//johnfitz -- dynamic gamedir stuff -- modified by QuakeSpasm team.
//==============================================================================
void ExtraMaps_NewGame ( void ) ;
static void COM_Game_f ( void )
{
if ( Cmd_Argc ( ) > 1 )
{
2017-09-17 02:12:53 +00:00
int i , pri ;
char paths [ 1024 ] ;
2014-09-08 21:10:33 +00:00
if ( ! registered . value ) //disable shareware quake
{
Con_Printf ( " You must have the registered version to use modified games \n " ) ;
return ;
}
2017-09-17 02:12:53 +00:00
* paths = 0 ;
q_strlcat ( paths , GAMENAME , sizeof ( paths ) ) ;
for ( pri = 0 ; pri < = 1 ; pri + + )
2014-09-08 21:10:33 +00:00
{
2017-09-17 02:12:53 +00:00
for ( i = 1 ; i < Cmd_Argc ( ) ; i + + )
{
const char * p = Cmd_Argv ( i ) ;
if ( ! * p )
p = GAMENAME ;
if ( pri = = 0 )
{
if ( * p ! = ' - ' )
continue ;
p + + ;
}
else if ( * p = = ' - ' )
continue ;
if ( ! * p | | ! strcmp ( p , " . " ) | | strstr ( p , " .. " ) | | strstr ( p , " / " ) | | strstr ( p , " \\ " ) | | strstr ( p , " : " ) )
{
Con_Printf ( " gamedir should be a single directory name, not a path \n " ) ;
return ;
}
2014-09-08 21:10:33 +00:00
2017-09-17 02:12:53 +00:00
if ( ! q_strcasecmp ( p , GAMENAME ) )
continue ; //don't add id1, its not interesting enough.
if ( * paths )
q_strlcat ( paths , " ; " , sizeof ( paths ) ) ;
q_strlcat ( paths , p , sizeof ( paths ) ) ;
changes/fixes to 'game' command, to replicate FitzQuake Mark V behavior:
* make 'game' command to strip all mission pack support
* make 'game' command to accept an optional second mission pack argument,
i.e. -hipnotic, -rogue or -quoth.
* so the new behavior does:
game id1 --> really returns to bare id1 game, doesn't accept any mission pack arguments
game xxx -hipnotic --> strip down to id1 game, load hipnotic and load xxx on top of them
game xxx --> strip down to id1 game and load xxx on top of it
* additionally, some extravaganza:
game xxx --> if the game is already xxx, but the engine was started with -hiptonic
or -rogue or -quoth, strip down to id1 and reload xxx on top of bare id1
game xxx -hipnotic --> if the game is already xxx, but the engine was started without
-hiptonic, strip down to id1, load hipnotic and reload xxx on top of them
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1010 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-09 07:13:20 +00:00
}
}
2017-09-17 02:12:53 +00:00
if ( ! q_strcasecmp ( paths , COM_GetGameNames ( true ) ) )
2014-09-08 21:10:33 +00:00
{
2017-09-17 02:12:53 +00:00
Con_Printf ( " \" game \" is already \" %s \" \n " , COM_GetGameNames ( true ) ) ;
return ;
2014-09-08 21:10:33 +00:00
}
com_modified = true ;
//Kill the server
CL_Disconnect ( ) ;
Host_ShutdownServer ( true ) ;
//Write config file
2017-09-17 02:12:53 +00:00
//fixme -- writing configs without reloading when switching between many mods is SERIOUSLY dangerous. ignore if no 'exec default.cfg' commands were used?
2014-09-08 21:10:33 +00:00
Host_WriteConfiguration ( ) ;
2017-09-17 02:12:53 +00:00
COM_ResetGameDirectories ( paths ) ;
2014-09-08 21:10:33 +00:00
//clear out and reload appropriate data
Cache_Flush ( ) ;
Mod_ResetAll ( ) ;
if ( ! isDedicated )
{
TexMgr_NewGame ( ) ;
Draw_NewGame ( ) ;
R_NewGame ( ) ;
}
ExtraMaps_NewGame ( ) ;
2015-05-30 02:28:58 +00:00
DemoList_Rebuild ( ) ;
2014-09-08 21:10:33 +00:00
2017-09-17 02:12:53 +00:00
Con_Printf ( " \" game \" changed to \" %s \" \n " , COM_GetGameNames ( true ) ) ;
2017-06-23 22:02:49 +00:00
VID_Lock ( ) ;
Cbuf_AddText ( " exec quake.rc \n " ) ;
Cbuf_AddText ( " vid_unlock \n " ) ;
2014-09-08 21:10:33 +00:00
}
else //Diplay the current gamedir
2017-09-17 02:12:53 +00:00
Con_Printf ( " \" game \" is \" %s \" \n " , COM_GetGameNames ( true ) ) ;
2014-09-08 21:10:33 +00:00
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = =
COM_InitFilesystem
= = = = = = = = = = = = = = = = =
*/
2010-03-01 11:55:13 +00:00
void COM_InitFilesystem ( void ) //johnfitz -- modified based on topaz's tutorial
2010-02-15 23:26:55 +00:00
{
int i , j ;
2017-09-17 02:12:53 +00:00
const char * p ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
Cvar_RegisterVariable ( & allow_download ) ;
2011-12-29 15:10:18 +00:00
Cvar_RegisterVariable ( & registered ) ;
Cvar_RegisterVariable ( & cmdline ) ;
Cmd_AddCommand ( " path " , COM_Path_f ) ;
2014-09-08 21:10:33 +00:00
Cmd_AddCommand ( " game " , COM_Game_f ) ; //johnfitz
2017-09-17 02:12:53 +00:00
Cmd_AddCommand ( " gamedir " , COM_Game_f ) ; //Spike -- alternative name for it, consistent with quakeworld and a few other engines
2011-12-29 15:10:18 +00:00
2010-02-15 23:26:55 +00:00
i = COM_CheckParm ( " -basedir " ) ;
if ( i & & i < com_argc - 1 )
2011-12-27 13:15:31 +00:00
q_strlcpy ( com_basedir , com_argv [ i + 1 ] , sizeof ( com_basedir ) ) ;
2010-02-15 23:26:55 +00:00
else
2011-12-27 13:15:31 +00:00
q_strlcpy ( com_basedir , host_parms - > basedir , sizeof ( com_basedir ) ) ;
2010-02-15 23:26:55 +00:00
2010-03-01 11:55:13 +00:00
j = strlen ( com_basedir ) ;
2014-09-09 11:50:38 +00:00
if ( j < 1 ) Sys_Error ( " Bad argument to -basedir " ) ;
if ( ( com_basedir [ j - 1 ] = = ' \\ ' ) | | ( com_basedir [ j - 1 ] = = ' / ' ) )
com_basedir [ j - 1 ] = 0 ;
2010-02-15 23:26:55 +00:00
2020-07-22 01:37:16 +00:00
i = COM_CheckParmNext ( i , " -basegame " ) ;
if ( i )
{ //-basegame:
// a) replaces all hardcoded dirs (read: alternative to id1)
// b) isn't flushed on normal gamedir switches (like id1).
com_modified = true ; //shouldn't be relevant when not using id content... but we don't really know.
for ( ; ; i = COM_CheckParmNext ( i , " -basegame " ) )
{
if ( ! i | | i > = com_argc - 1 )
break ;
p = com_argv [ i + 1 ] ;
if ( ! * p | | ! strcmp ( p , " . " ) | | strstr ( p , " .. " ) | | * p = = ' / ' | | * p = = ' \\ ' | | strstr ( p , " : " ) )
Sys_Error ( " gamedir should be a single directory name, not a path \n " ) ;
if ( p ! = NULL )
COM_AddGameDirectory ( p ) ;
}
}
else
{
// start up with GAMENAME by default (id1)
COM_AddGameDirectory ( GAMENAME ) ;
}
2010-02-20 08:50:31 +00:00
changes/fixes to 'game' command, to replicate FitzQuake Mark V behavior:
* make 'game' command to strip all mission pack support
* make 'game' command to accept an optional second mission pack argument,
i.e. -hipnotic, -rogue or -quoth.
* so the new behavior does:
game id1 --> really returns to bare id1 game, doesn't accept any mission pack arguments
game xxx -hipnotic --> strip down to id1 game, load hipnotic and load xxx on top of them
game xxx --> strip down to id1 game and load xxx on top of it
* additionally, some extravaganza:
game xxx --> if the game is already xxx, but the engine was started with -hiptonic
or -rogue or -quoth, strip down to id1 and reload xxx on top of bare id1
game xxx -hipnotic --> if the game is already xxx, but the engine was started without
-hiptonic, strip down to id1, load hipnotic and reload xxx on top of them
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1010 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-09 07:13:20 +00:00
/* this is the end of our base searchpath:
* any set gamedirs , such as those from - game command line
* arguments or by the ' game ' console command will be freed
* up to here upon a new game command . */
com_base_searchpaths = com_searchpaths ;
2017-09-17 02:12:53 +00:00
COM_ResetGameDirectories ( " " ) ;
changes/fixes to 'game' command, to replicate FitzQuake Mark V behavior:
* make 'game' command to strip all mission pack support
* make 'game' command to accept an optional second mission pack argument,
i.e. -hipnotic, -rogue or -quoth.
* so the new behavior does:
game id1 --> really returns to bare id1 game, doesn't accept any mission pack arguments
game xxx -hipnotic --> strip down to id1 game, load hipnotic and load xxx on top of them
game xxx --> strip down to id1 game and load xxx on top of it
* additionally, some extravaganza:
game xxx --> if the game is already xxx, but the engine was started with -hiptonic
or -rogue or -quoth, strip down to id1 and reload xxx on top of bare id1
game xxx -hipnotic --> if the game is already xxx, but the engine was started without
-hiptonic, strip down to id1, load hipnotic and reload xxx on top of them
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1010 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-09 07:13:20 +00:00
// add mission pack requests (only one should be specified)
2010-02-15 23:26:55 +00:00
if ( COM_CheckParm ( " -rogue " ) )
2017-09-17 02:12:53 +00:00
COM_AddGameDirectory ( " rogue " ) ;
2010-02-15 23:26:55 +00:00
if ( COM_CheckParm ( " -hipnotic " ) )
2017-09-17 02:12:53 +00:00
COM_AddGameDirectory ( " hipnotic " ) ;
2010-02-15 23:26:55 +00:00
if ( COM_CheckParm ( " -quoth " ) )
2017-09-17 02:12:53 +00:00
COM_AddGameDirectory ( " quoth " ) ;
2014-09-08 18:20:47 +00:00
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
for ( i = 0 ; ; )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
i = COM_CheckParmNext ( i , " -game " ) ;
if ( ! i | | i > = com_argc - 1 )
break ;
p = com_argv [ i + 1 ] ;
if ( ! * p | | ! strcmp ( p , " . " ) | | strstr ( p , " .. " ) | | * p = = ' / ' | | * p = = ' \\ ' | | strstr ( p , " : " ) )
2014-09-08 21:10:33 +00:00
Sys_Error ( " gamedir should be a single directory name, not a path \n " ) ;
2010-02-15 23:26:55 +00:00
com_modified = true ;
2017-09-17 02:12:53 +00:00
if ( p ! = NULL )
COM_AddGameDirectory ( p ) ;
2010-02-15 23:26:55 +00:00
}
2011-12-29 15:10:18 +00:00
COM_CheckRegistered ( ) ;
2010-02-15 23:26:55 +00:00
}
2010-12-30 16:50:15 +00:00
/* The following FS_*() stdio replacements are necessary if one is
* to perform non - sequential reads on files reopened on pak files
* because we need the bookkeeping about file start / end positions .
* Allocating and filling in the fshandle_t structure is the users '
* responsibility when the file is initially opened . */
size_t FS_fread ( void * ptr , size_t size , size_t nmemb , fshandle_t * fh )
{
2011-02-08 11:00:29 +00:00
long byte_size ;
long bytes_read ;
size_t nmemb_read ;
2010-12-30 16:50:15 +00:00
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
errno = EBADF ;
2010-12-30 16:50:15 +00:00
return 0 ;
}
2013-09-25 11:01:12 +00:00
if ( ! ptr ) {
errno = EFAULT ;
2010-12-30 16:50:15 +00:00
return 0 ;
}
2013-09-25 11:01:12 +00:00
if ( ! size | | ! nmemb ) { /* no error, just zero bytes wanted */
errno = 0 ;
2010-12-30 16:50:15 +00:00
return 0 ;
}
2011-02-08 11:00:29 +00:00
byte_size = nmemb * size ;
if ( byte_size > fh - > length - fh - > pos ) /* just read to end */
byte_size = fh - > length - fh - > pos ;
bytes_read = fread ( ptr , 1 , byte_size , fh - > file ) ;
fh - > pos + = bytes_read ;
2010-12-30 16:50:15 +00:00
2011-02-08 11:00:29 +00:00
/* fread() must return the number of elements read,
* not the total number of bytes . */
nmemb_read = bytes_read / size ;
2010-12-30 16:50:15 +00:00
/* even if the last member is only read partially
2011-02-08 11:00:29 +00:00
* it is counted as a whole in the return value . */
if ( bytes_read % size )
nmemb_read + + ;
2010-12-30 16:50:15 +00:00
2011-02-08 11:00:29 +00:00
return nmemb_read ;
2010-12-30 16:50:15 +00:00
}
int FS_fseek ( fshandle_t * fh , long offset , int whence )
{
/* I don't care about 64 bit off_t or fseeko() here.
* the quake / hexen2 file system is 32 bits , anyway . */
int ret ;
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
2010-12-30 16:50:15 +00:00
errno = EBADF ;
return - 1 ;
}
/* the relative file position shouldn't be smaller
* than zero or bigger than the filesize . */
switch ( whence )
{
case SEEK_SET :
break ;
case SEEK_CUR :
offset + = fh - > pos ;
break ;
case SEEK_END :
offset = fh - > length + offset ;
break ;
default :
errno = EINVAL ;
return - 1 ;
}
2013-09-25 11:01:12 +00:00
if ( offset < 0 ) {
2010-12-30 16:50:15 +00:00
errno = EINVAL ;
return - 1 ;
}
if ( offset > fh - > length ) /* just seek to end */
offset = fh - > length ;
ret = fseek ( fh - > file , fh - > start + offset , SEEK_SET ) ;
if ( ret < 0 )
return ret ;
fh - > pos = offset ;
return 0 ;
}
int FS_fclose ( fshandle_t * fh )
{
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
2010-12-30 16:50:15 +00:00
errno = EBADF ;
return - 1 ;
}
return fclose ( fh - > file ) ;
}
long FS_ftell ( fshandle_t * fh )
{
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
2010-12-30 16:50:15 +00:00
errno = EBADF ;
return - 1 ;
}
return fh - > pos ;
}
void FS_rewind ( fshandle_t * fh )
{
2013-09-25 11:01:12 +00:00
if ( ! fh ) return ;
2010-12-30 16:50:15 +00:00
clearerr ( fh - > file ) ;
fseek ( fh - > file , fh - > start , SEEK_SET ) ;
fh - > pos = 0 ;
}
int FS_feof ( fshandle_t * fh )
{
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
errno = EBADF ;
return - 1 ;
}
2010-12-30 16:50:15 +00:00
if ( fh - > pos > = fh - > length )
return - 1 ;
return 0 ;
}
int FS_ferror ( fshandle_t * fh )
{
2013-09-25 11:01:12 +00:00
if ( ! fh ) {
errno = EBADF ;
return - 1 ;
}
2010-12-30 16:50:15 +00:00
return ferror ( fh - > file ) ;
}
2013-09-27 19:51:26 +00:00
int FS_fgetc ( fshandle_t * fh )
{
if ( ! fh ) {
errno = EBADF ;
return EOF ;
}
if ( fh - > pos > = fh - > length )
return EOF ;
fh - > pos + = 1 ;
return fgetc ( fh - > file ) ;
}
2011-12-24 12:03:29 +00:00
char * FS_fgets ( char * s , int size , fshandle_t * fh )
{
char * ret ;
if ( FS_feof ( fh ) )
return NULL ;
if ( size > ( fh - > length - fh - > pos ) + 1 )
size = ( fh - > length - fh - > pos ) + 1 ;
ret = fgets ( s , size , fh - > file ) ;
fh - > pos = ftell ( fh - > file ) - fh - > start ;
return ret ;
}
2013-09-25 11:01:12 +00:00
long FS_filelength ( fshandle_t * fh )
{
if ( ! fh ) {
errno = EBADF ;
return - 1 ;
}
return fh - > length ;
}
2017-09-17 02:12:53 +00:00
//for compat with dpp7 protocols, and mods that cba to precache things.
void COM_Effectinfo_Enumerate ( int ( * cb ) ( const char * pname ) )
{
int i ;
const char * f , * e ;
char * buf ;
static const char * dpnames [ ] =
{
" TE_GUNSHOT " ,
" TE_GUNSHOTQUAD " ,
" TE_SPIKE " ,
" TE_SPIKEQUAD " ,
" TE_SUPERSPIKE " ,
" TE_SUPERSPIKEQUAD " ,
" TE_WIZSPIKE " ,
" TE_KNIGHTSPIKE " ,
" TE_EXPLOSION " ,
" TE_EXPLOSIONQUAD " ,
" TE_TAREXPLOSION " ,
" TE_TELEPORT " ,
" TE_LAVASPLASH " ,
" TE_SMALLFLASH " ,
" TE_FLAMEJET " ,
" EF_FLAME " ,
" TE_BLOOD " ,
" TE_SPARK " ,
" TE_PLASMABURN " ,
" TE_TEI_G3 " ,
" TE_TEI_SMOKE " ,
" TE_TEI_BIGEXPLOSION " ,
" TE_TEI_PLASMAHIT " ,
" EF_STARDUST " ,
" TR_ROCKET " ,
" TR_GRENADE " ,
" TR_BLOOD " ,
" TR_WIZSPIKE " ,
" TR_SLIGHTBLOOD " ,
" TR_KNIGHTSPIKE " ,
" TR_VORESPIKE " ,
" TR_NEHAHRASMOKE " ,
" TR_NEXUIZPLASMA " ,
" TR_GLOWTRAIL " ,
" SVC_PARTICLE " ,
NULL
} ;
buf = ( char * ) COM_LoadMallocFile ( " effectinfo.txt " , NULL ) ;
if ( ! buf )
return ;
for ( i = 0 ; dpnames [ i ] ; i + + )
cb ( dpnames [ i ] ) ;
for ( f = buf ; f ; f = e )
{
e = COM_Parse ( f ) ;
if ( ! strcmp ( com_token , " effect " ) )
{
e = COM_Parse ( e ) ;
cb ( com_token ) ;
}
while ( e & & * e & & * e ! = ' \n ' )
e + + ;
}
free ( buf ) ;
}