diff options
Diffstat (limited to 'src/qcommon/q_shared.c')
-rw-r--r-- | src/qcommon/q_shared.c | 634 |
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 ); +} |