summaryrefslogtreecommitdiff
path: root/src/qcommon/q_shared.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/qcommon/q_shared.c')
-rw-r--r--src/qcommon/q_shared.c634
1 files changed, 408 insertions, 226 deletions
diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
index 2ac5537..938a7e5 100644
--- a/src/qcommon/q_shared.c
+++ b/src/qcommon/q_shared.c
@@ -1,13 +1,14 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
-Copyright (C) 2000-2006 Tim Angus
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous 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,
+published by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
Tremulous is distributed in the hope that it will be
@@ -16,8 +17,8 @@ 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 Tremulous; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
===========================================================================
*/
//
@@ -56,50 +57,77 @@ char *COM_SkipPath (char *pathname)
/*
============
+COM_GetExtension
+============
+*/
+const char *COM_GetExtension( const char *name )
+{
+ const char *dot = strrchr(name, '.'), *slash;
+ if (dot && (!(slash = strrchr(name, '/')) || slash < dot))
+ return dot + 1;
+ else
+ return "";
+}
+
+
+/*
+============
COM_StripExtension
============
*/
-void COM_StripExtension( const char *in, char *out, int destsize ) {
- int length;
+void COM_StripExtension( const char *in, char *out, int destsize )
+{
+ const char *dot = strrchr(in, '.'), *slash;
- Q_strncpyz(out, in, destsize);
+ if (dot && (!(slash = strrchr(in, '/')) || slash < dot))
+ destsize = (destsize < dot-in+1 ? destsize : dot-in+1);
- length = strlen(out)-1;
- while (length > 0 && out[length] != '.')
+ if ( in == out && destsize > 1 )
+ out[destsize-1] = '\0';
+ else
+ Q_strncpyz(out, in, destsize);
+}
+
+/*
+============
+COM_CompareExtension
+
+string compare the end of the strings and return qtrue if strings match
+============
+*/
+qboolean COM_CompareExtension(const char *in, const char *ext)
+{
+ int inlen, extlen;
+
+ inlen = strlen(in);
+ extlen = strlen(ext);
+
+ if(extlen <= inlen)
{
- length--;
- if (out[length] == '/')
- return; // no extension
+ in += inlen - extlen;
+
+ if(!Q_stricmp(in, ext))
+ return qtrue;
}
- if (length)
- out[length] = 0;
+
+ return qfalse;
}
-
/*
==================
COM_DefaultExtension
+
+if path doesn't have an extension, then append
+ the specified one (which should include the .)
==================
*/
-void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
- char oldPath[MAX_QPATH];
- char *src;
-
-//
-// if path doesn't have a .EXT, append extension
-// (extension should include the .)
-//
- src = path + strlen(path) - 1;
-
- while (*src != '/' && src != path) {
- if ( *src == '.' ) {
- return; // it has an extension
- }
- src--;
- }
-
- Q_strncpyz( oldPath, path, sizeof( oldPath ) );
- Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
+void COM_DefaultExtension( char *path, int maxSize, const char *extension )
+{
+ const char *dot = strrchr(path, '.'), *slash;
+ if (dot && (!(slash = strrchr(path, '/')) || slash < dot))
+ return;
+ else
+ Q_strcat(path, maxSize, extension);
}
/*
@@ -131,6 +159,24 @@ float BigFloat (const float *l) {return _BigFloat(l);}
float LittleFloat (const float *l) {return _LittleFloat(l);}
*/
+void CopyShortSwap(void *dest, void *src)
+{
+ byte *to = dest, *from = src;
+
+ to[0] = from[1];
+ to[1] = from[0];
+}
+
+void CopyLongSwap(void *dest, void *src)
+{
+ byte *to = dest, *from = src;
+
+ to[0] = from[3];
+ to[1] = from[2];
+ to[2] = from[1];
+ to[3] = from[0];
+}
+
short ShortSwap (short l)
{
byte b1,b2;
@@ -158,47 +204,17 @@ int LongSwap (int l)
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
-int LongNoSwap (int l)
-{
- return l;
-}
-
-qint64 Long64Swap (qint64 ll)
-{
- qint64 result;
-
- result.b0 = ll.b7;
- result.b1 = ll.b6;
- result.b2 = ll.b5;
- result.b3 = ll.b4;
- result.b4 = ll.b3;
- result.b5 = ll.b2;
- result.b6 = ll.b1;
- result.b7 = ll.b0;
-
- return result;
-}
-
-qint64 Long64NoSwap (qint64 ll)
+float FloatSwap(const float *f)
{
- return ll;
-}
-
-typedef union {
- float f;
- unsigned int i;
-} _FloatByteUnion;
-
-float FloatSwap (const float *f) {
- _FloatByteUnion out;
+ floatint_t out;
out.f = *f;
- out.i = LongSwap(out.i);
+ out.ui = LongSwap(out.ui);
return out.f;
}
-float FloatNoSwap (const float *f)
+float FloatNoSwap(const float *f)
{
return *f;
}
@@ -251,15 +267,22 @@ PARSING
static char com_token[MAX_TOKEN_CHARS];
static char com_parsename[MAX_TOKEN_CHARS];
static int com_lines;
+static int com_tokenline;
void COM_BeginParseSession( const char *name )
{
- com_lines = 0;
+ com_lines = 1;
+ com_tokenline = 0;
Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
}
int COM_GetCurrentParseLine( void )
{
+ if ( com_tokenline )
+ {
+ return com_tokenline;
+ }
+
return com_lines;
}
@@ -274,10 +297,10 @@ void COM_ParseError( char *format, ... )
static char string[4096];
va_start (argptr, format);
- vsprintf (string, format, argptr);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
- Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
+ Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
}
void COM_ParseWarning( char *format, ... )
@@ -286,10 +309,10 @@ void COM_ParseWarning( char *format, ... )
static char string[4096];
va_start (argptr, format);
- vsprintf (string, format, argptr);
+ Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
- Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
+ Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
}
/*
@@ -340,52 +363,53 @@ int COM_Compress( char *data_p ) {
in++;
if ( *in )
in += 2;
- // record when we hit a newline
- } else if ( c == '\n' || c == '\r' ) {
- newline = qtrue;
- in++;
- // record when we hit whitespace
- } else if ( c == ' ' || c == '\t') {
- whitespace = qtrue;
- in++;
- // an actual token
+ // record when we hit a newline
+ } else if ( c == '\n' || c == '\r' ) {
+ newline = qtrue;
+ in++;
+ // record when we hit whitespace
+ } else if ( c == ' ' || c == '\t') {
+ whitespace = qtrue;
+ in++;
+ // an actual token
} else {
- // if we have a pending newline, emit it (and it counts as whitespace)
- if (newline) {
- *out++ = '\n';
- newline = qfalse;
- whitespace = qfalse;
- } if (whitespace) {
- *out++ = ' ';
- whitespace = qfalse;
- }
-
- // copy quoted strings unmolested
- if (c == '"') {
- *out++ = c;
- in++;
- while (1) {
- c = *in;
- if (c && c != '"') {
- *out++ = c;
- in++;
- } else {
- break;
- }
- }
- if (c == '"') {
- *out++ = c;
- in++;
- }
- } else {
- *out = c;
- out++;
- in++;
- }
+ // if we have a pending newline, emit it (and it counts as whitespace)
+ if (newline) {
+ *out++ = '\n';
+ newline = qfalse;
+ whitespace = qfalse;
+ } if (whitespace) {
+ *out++ = ' ';
+ whitespace = qfalse;
+ }
+
+ // copy quoted strings unmolested
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ while (1) {
+ c = *in;
+ if (c && c != '"') {
+ *out++ = c;
+ in++;
+ } else {
+ break;
+ }
+ }
+ if (c == '"') {
+ *out++ = c;
+ in++;
+ }
+ } else {
+ *out = c;
+ out++;
+ in++;
+ }
}
}
+
+ *out = 0;
}
- *out = 0;
return out - data_p;
}
@@ -398,6 +422,7 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
data = *data_p;
len = 0;
com_token[0] = 0;
+ com_tokenline = 0;
// make sure incoming data is valid
if ( !data )
@@ -437,6 +462,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
data += 2;
while ( *data && ( *data != '*' || data[1] != '/' ) )
{
+ if ( *data == '\n' )
+ {
+ com_lines++;
+ }
data++;
}
if ( *data )
@@ -450,6 +479,9 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
}
}
+ // token starts on this line
+ com_tokenline = com_lines;
+
// handle quoted strings
if (c == '\"')
{
@@ -463,6 +495,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
*data_p = ( char * ) data;
return com_token;
}
+ if ( c == '\n' )
+ {
+ com_lines++;
+ }
if (len < MAX_TOKEN_CHARS - 1)
{
com_token[len] = c;
@@ -481,8 +517,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
}
data++;
c = *data;
- if ( c == '\n' )
- com_lines++;
} while (c>32);
com_token[len] = 0;
@@ -491,62 +525,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
return com_token;
}
-
-#if 0
-// no longer used
-/*
-===============
-COM_ParseInfos
-===============
-*/
-int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
- char *token;
- int count;
- char key[MAX_TOKEN_CHARS];
-
- count = 0;
-
- while ( 1 ) {
- token = COM_Parse( &buf );
- if ( !token[0] ) {
- break;
- }
- if ( strcmp( token, "{" ) ) {
- Com_Printf( "Missing { in info file\n" );
- break;
- }
-
- if ( count == max ) {
- Com_Printf( "Max infos exceeded\n" );
- break;
- }
-
- infos[count][0] = 0;
- while ( 1 ) {
- token = COM_ParseExt( &buf, qtrue );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = COM_ParseExt( &buf, qfalse );
- if ( !token[0] ) {
- strcpy( token, "<NULL>" );
- }
- Info_SetValueForKey( infos[count], key, token );
- }
- count++;
- }
-
- return count;
-}
-#endif
-
-
/*
==================
COM_MatchToken
@@ -566,16 +544,14 @@ void COM_MatchToken( char **buf_p, char *match ) {
=================
SkipBracedSection
-The next token should be an open brace.
+The next token should be an open brace or set depth to 1 if already parsed it.
Skips until a matching close brace is found.
Internal brace depths are properly skipped.
=================
*/
-void SkipBracedSection (char **program) {
+qboolean SkipBracedSection (char **program, int depth) {
char *token;
- int depth;
- depth = 0;
do {
token = COM_ParseExt( program, qtrue );
if( token[1] == 0 ) {
@@ -587,6 +563,8 @@ void SkipBracedSection (char **program) {
}
}
} while( depth && *program );
+
+ return ( depth == 0 );
}
/*
@@ -599,6 +577,10 @@ void SkipRestOfLine ( char **data ) {
int c;
p = *data;
+
+ if ( !*p )
+ return;
+
while ( (c = *p++) != 0 ) {
if ( c == '\n' ) {
com_lines++;
@@ -648,6 +630,45 @@ void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
COM_MatchToken( buf_p, ")" );
}
+/*
+===================
+Com_HexStrToInt
+===================
+*/
+int Com_HexStrToInt( const char *str )
+{
+ if ( !str || !str[ 0 ] )
+ return -1;
+
+ // check for hex code
+ if( str[ 0 ] == '0' && str[ 1 ] == 'x' )
+ {
+ size_t i;
+ int n = 0;
+
+ for( i = 2; i < strlen( str ); i++ )
+ {
+ char digit;
+
+ n *= 16;
+
+ digit = tolower( str[ i ] );
+
+ if( digit >= '0' && digit <= '9' )
+ digit -= '0';
+ else if( digit >= 'a' && digit <= 'f' )
+ digit = digit - 'a' + 10;
+ else
+ return -1;
+
+ n += digit;
+ }
+
+ return n;
+ }
+
+ return -1;
+}
/*
============================================================================
@@ -685,32 +706,56 @@ int Q_isalpha( int c )
return ( 0 );
}
-int Q_isdigit( int c )
+qboolean Q_isanumber( const char *s )
{
- if ((c >= '0' && c <= '9'))
- return ( 1 );
- return ( 0 );
+ char *p;
+ double UNUSED_VAR d;
+
+ if( *s == '\0' )
+ return qfalse;
+
+ d = strtod( s, &p );
+
+ return *p == '\0';
}
-char* Q_strrchr( const char* string, int c )
+qboolean Q_isintegral( float f )
{
- char cc = c;
- char *s;
- char *sp=(char *)0;
+ return (int)f == f;
+}
- s = (char*)string;
+#ifdef _MSC_VER
+/*
+=============
+Q_vsnprintf
+
+Special wrapper function for Microsoft's broken _vsnprintf() function.
+MinGW comes with its own snprintf() which is not broken.
+=============
+*/
+
+int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ int retval;
+
+ retval = _vsnprintf(str, size, format, ap);
- while (*s)
+ if(retval < 0 || retval == size)
{
- if (*s == cc)
- sp = s;
- s++;
+ // Microsoft doesn't adhere to the C99 standard of vsnprintf,
+ // which states that the return value must be the number of
+ // bytes written if the output string had sufficient length.
+ //
+ // Obviously we cannot determine that value from Microsoft's
+ // implementation, so we have no choice but to return size.
+
+ str[size - 1] = '\0';
+ return size;
}
- if (cc == 0)
- sp = s;
-
- return sp;
+
+ return retval;
}
+#endif
/*
=============
@@ -720,7 +765,6 @@ Safe strncpy that ensures a trailing zero
=============
*/
void Q_strncpyz( char *dest, const char *src, int destsize ) {
- // bk001129 - also NULL dest
if ( !dest ) {
Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
}
@@ -738,7 +782,6 @@ void Q_strncpyz( char *dest, const char *src, int destsize ) {
int Q_stricmpn (const char *s1, const char *s2, int n) {
int c1, c2;
- // bk001129 - moved in 1.17 fix not in id codebase
if ( s1 == NULL ) {
if ( s2 == NULL )
return 0;
@@ -832,6 +875,38 @@ void Q_strcat( char *dest, int size, const char *src ) {
Q_strncpyz( dest + l1, src, size - l1 );
}
+/*
+* Find the first occurrence of find in s.
+*/
+const char *Q_stristr( const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0)
+ {
+ if (c >= 'a' && c <= 'z')
+ {
+ c -= ('a' - 'A');
+ }
+ len = strlen(find);
+ do
+ {
+ do
+ {
+ if ((sc = *s++) == 0)
+ return NULL;
+ if (sc >= 'a' && sc <= 'z')
+ {
+ sc -= ('a' - 'A');
+ }
+ } while (sc != c);
+ } while (Q_stricmpn(s, find, len) != 0);
+ s--;
+ }
+ return s;
+}
+
int Q_PrintStrlen( const char *string ) {
int len;
@@ -877,29 +952,52 @@ char *Q_CleanStr( char *string ) {
return string;
}
+int Q_CountChar(const char *string, char tocount)
+{
+ int count;
+
+ for(count = 0; *string; string++)
+ {
+ if(*string == tocount)
+ count++;
+ }
+
+ return count;
+}
-void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
+void Q_StripIndentMarker(char *string)
+{
+ int i, j;
+
+ for (i = j = 0; string[i]; i++) {
+ if (string[i] != INDENT_MARKER) {
+ string[j++] = string[i];
+ }
+ }
+ string[j] = 0;
+}
+
+void Q_ParseNewlines( char *dest, const char *src, int destsize )
+{
+ for( ; *src && destsize > 1; src++, destsize-- )
+ *dest++ = ( ( *src == '\\' && *( ++src ) == 'n' ) ? '\n' : *src );
+ *dest++ = '\0';
+}
+
+int QDECL Com_sprintf(char *dest, int size, const char *fmt, ...)
+{
int len;
va_list argptr;
- char bigbuffer[32000]; // big, but small enough to fit in PPC stack
va_start (argptr,fmt);
- len = vsprintf (bigbuffer,fmt,argptr);
+ len = Q_vsnprintf(dest, size, fmt, argptr);
va_end (argptr);
- if ( len >= sizeof( bigbuffer ) ) {
- Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
- }
- if (len >= size) {
- Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
-#ifdef _DEBUG
- __asm {
- int 3;
- }
-#endif
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
+ if(len >= size)
+ Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1);
+
+ return len;
+}
/*
============
@@ -907,20 +1005,19 @@ va
does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
-FIXME: make this buffer size safe someday
============
*/
-char * QDECL va( char *format, ... ) {
+const char * QDECL va(const char *format, ... ) {
va_list argptr;
- static char string[2][32000]; // in case va is called by nested functions
- static int index = 0;
- char *buf;
+ static char string[2][32000]; // in case va is called by nested functions
+ static int index = 0;
+ char *buf;
buf = string[index & 1];
index++;
va_start (argptr, format);
- vsprintf (buf, format,argptr);
+ Q_vsnprintf (buf, sizeof(*string), format, argptr);
va_end (argptr);
return buf;
@@ -1100,7 +1197,8 @@ void Info_RemoveKey( char *s, const char *key ) {
if (!strcmp (key, pkey) )
{
- strcpy (start, s); // remove this part
+ memmove(start, s, strlen(s) + 1); // remove this part
+
return;
}
@@ -1155,7 +1253,7 @@ void Info_RemoveKey_Big( char *s, const char *key ) {
if (!strcmp (key, pkey) )
{
- strcpy (start, s); // remove this part
+ memmove(start, s, strlen(s) + 1); // remove this part
return;
}
@@ -1241,6 +1339,7 @@ void Info_SetValueForKey( char *s, const char *key, const char *value ) {
Info_SetValueForKey_Big
Changes or adds a key/value pair
+Includes and retains zero-length values
==================
*/
void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
@@ -1261,14 +1360,15 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
}
Info_RemoveKey_Big (s, key);
- if (!value || !strlen(value))
+ if (!value)
return;
Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
{
- Com_Printf ("BIG Info string length exceeded\n");
+ Com_Printf ("BIG Info string length exceeded: setting %s to %s "
+ "failed\n", key, value);
return;
}
@@ -1285,9 +1385,9 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
Com_CharIsOneOfCharset
==================
*/
-static qboolean Com_CharIsOneOfCharset( char c, char *set )
+static qboolean Com_CharIsOneOfCharset( char c, const char *set )
{
- int i;
+ size_t i;
for( i = 0; i < strlen( set ); i++ )
{
@@ -1303,7 +1403,7 @@ static qboolean Com_CharIsOneOfCharset( char c, char *set )
Com_SkipCharset
==================
*/
-char *Com_SkipCharset( char *s, char *sep )
+char *Com_SkipCharset( char *s, const char *sep )
{
char *p = s;
@@ -1323,7 +1423,7 @@ char *Com_SkipCharset( char *s, char *sep )
Com_SkipTokens
==================
*/
-char *Com_SkipTokens( char *s, int numTokens, char *sep )
+char *Com_SkipTokens( char *s, int numTokens, const char *sep )
{
int sepCount = 0;
char *p = s;
@@ -1345,3 +1445,85 @@ char *Com_SkipTokens( char *s, int numTokens, char *sep )
else
return s;
}
+
+/*
+============
+Com_ClientListContains
+============
+*/
+qboolean Com_ClientListContains( const clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return qfalse;
+ if( clientNum < 32 )
+ return ( ( list->lo & ( 1 << clientNum ) ) != 0 );
+ else
+ return ( ( list->hi & ( 1 << ( clientNum - 32 ) ) ) != 0 );
+}
+
+/*
+============
+Com_ClientListAdd
+============
+*/
+void Com_ClientListAdd( clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return;
+ if( clientNum < 32 )
+ list->lo |= ( 1 << clientNum );
+ else
+ list->hi |= ( 1 << ( clientNum - 32 ) );
+}
+
+/*
+============
+Com_ClientListRemove
+============
+*/
+void Com_ClientListRemove( clientList_t *list, int clientNum )
+{
+ if( clientNum < 0 || clientNum >= MAX_CLIENTS || !list )
+ return;
+ if( clientNum < 32 )
+ list->lo &= ~( 1 << clientNum );
+ else
+ list->hi &= ~( 1 << ( clientNum - 32 ) );
+}
+
+/*
+============
+Com_ClientListString
+============
+*/
+char *Com_ClientListString( const clientList_t *list )
+{
+ static char s[ 17 ];
+
+ s[ 0 ] = '\0';
+ if( !list )
+ return s;
+ Com_sprintf( s, sizeof( s ), "%08x%08x", list->hi, list->lo );
+ return s;
+}
+
+/*
+============
+Com_ClientListParse
+============
+*/
+void Com_ClientListParse( clientList_t *list, const char *s )
+{
+ char t[ 9 ];
+ if( !list )
+ return;
+ list->lo = 0;
+ list->hi = 0;
+ if( !s )
+ return;
+ if( strlen( s ) != 16 )
+ return;
+ Q_strncpyz( t, s, 9 );
+ sscanf( t, "%x", &list->hi );
+ sscanf( s + 8, "%x", &list->lo );
+}