aboutsummaryrefslogtreecommitdiffstats
path: root/code/splines/q_shared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'code/splines/q_shared.cpp')
-rwxr-xr-xcode/splines/q_shared.cpp1952
1 files changed, 976 insertions, 976 deletions
diff --git a/code/splines/q_shared.cpp b/code/splines/q_shared.cpp
index 00934dd..ecd2342 100755
--- a/code/splines/q_shared.cpp
+++ b/code/splines/q_shared.cpp
@@ -1,976 +1,976 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// q_shared.c -- stateless support routines that are included in each code dll
-#include "q_shared.hpp"
-
-/*
-============================================================================
-
-GROWLISTS
-
-============================================================================
-*/
-
-// malloc / free all in one place for debugging
-extern "C" void *Com_Allocate( int bytes );
-extern "C" void Com_Dealloc( void *ptr );
-
-void Com_InitGrowList( growList_t *list, int maxElements ) {
- list->maxElements = maxElements;
- list->currentElements = 0;
- list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
-}
-
-int Com_AddToGrowList( growList_t *list, void *data ) {
- void **old;
-
- if ( list->currentElements != list->maxElements ) {
- list->elements[list->currentElements] = data;
- return list->currentElements++;
- }
-
- // grow, reallocate and move
- old = list->elements;
-
- if ( list->maxElements < 0 ) {
- Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
- }
-
- if ( list->maxElements == 0 ) {
- // initialize the list to hold 100 elements
- Com_InitGrowList( list, 100 );
- return Com_AddToGrowList( list, data );
- }
-
- list->maxElements *= 2;
-
- Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
-
- list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
-
- if ( !list->elements ) {
- Com_Error( ERR_DROP, "Growlist alloc failed" );
- }
-
- memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
-
- Com_Dealloc( old );
-
- return Com_AddToGrowList( list, data );
-}
-
-void *Com_GrowListElement( const growList_t *list, int index ) {
- if ( index < 0 || index >= list->currentElements ) {
- Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
- index, list->currentElements );
- }
- return list->elements[index];
-}
-
-int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
- int i;
-
- for ( i = 0 ; i < list->currentElements ; i++ ) {
- if ( list->elements[i] == element ) {
- return i;
- }
- }
- return -1;
-}
-
-//============================================================================
-
-
-float Com_Clamp( float min, float max, float value ) {
- if ( value < min ) {
- return min;
- }
- if ( value > max ) {
- return max;
- }
- return value;
-}
-
-/*
-============
-Com_StringContains
-============
-*/
-const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
- int len, i, j;
-
- len = strlen(str1) - strlen(str2);
- for (i = 0; i <= len; i++, str1++) {
- for (j = 0; str2[j]; j++) {
- if (casesensitive) {
- if (str1[j] != str2[j]) {
- break;
- }
- }
- else {
- if (toupper(str1[j]) != toupper(str2[j])) {
- break;
- }
- }
- }
- if (!str2[j]) {
- return str1;
- }
- }
- return NULL;
-}
-
-/*
-============
-Com_Filter
-============
-*/
-int Com_Filter( const char *filter, const char *name, int casesensitive)
-{
- char buf[MAX_TOKEN_CHARS];
- const char *ptr;
- int i, found;
-
- while(*filter) {
- if (*filter == '*') {
- filter++;
- for (i = 0; *filter; i++) {
- if (*filter == '*' || *filter == '?') break;
- buf[i] = *filter;
- filter++;
- }
- buf[i] = '\0';
- if (strlen(buf)) {
- ptr = Com_StringContains(name, buf, casesensitive);
- if (!ptr) return qfalse;
- name = ptr + strlen(buf);
- }
- }
- else if (*filter == '?') {
- filter++;
- name++;
- }
- else if (*filter == '[' && *(filter+1) == '[') {
- filter++;
- }
- else if (*filter == '[') {
- filter++;
- found = qfalse;
- while(*filter && !found) {
- if (*filter == ']' && *(filter+1) != ']') break;
- if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
- if (casesensitive) {
- if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
- }
- else {
- if (toupper(*name) >= toupper(*filter) &&
- toupper(*name) <= toupper(*(filter+2))) found = qtrue;
- }
- filter += 3;
- }
- else {
- if (casesensitive) {
- if (*filter == *name) found = qtrue;
- }
- else {
- if (toupper(*filter) == toupper(*name)) found = qtrue;
- }
- filter++;
- }
- }
- if (!found) return qfalse;
- while(*filter) {
- if (*filter == ']' && *(filter+1) != ']') break;
- filter++;
- }
- filter++;
- name++;
- }
- else {
- if (casesensitive) {
- if (*filter != *name) return qfalse;
- }
- else {
- if (toupper(*filter) != toupper(*name)) return qfalse;
- }
- filter++;
- name++;
- }
- }
- return qtrue;
-}
-
-
-/*
-================
-Com_HashString
-
-================
-*/
-int Com_HashString( const char *fname ) {
- int i;
- long hash;
- char letter;
-
- hash = 0;
- i = 0;
- while (fname[i] != '\0') {
- letter = tolower(fname[i]);
- if (letter =='.') break; // don't include extension
- if (letter =='\\') letter = '/'; // damn path names
- hash+=(long)(letter)*(i+119);
- i++;
- }
- hash &= (FILE_HASH_SIZE-1);
- return hash;
-}
-
-
-/*
-============
-Com_SkipPath
-============
-*/
-char *Com_SkipPath (char *pathname)
-{
- char *last;
-
- last = pathname;
- while (*pathname)
- {
- if (*pathname=='/')
- last = pathname+1;
- pathname++;
- }
- return last;
-}
-
-/*
-============
-Com_StripExtension
-============
-*/
-void Com_StripExtension( const char *in, char *out ) {
- while ( *in && *in != '.' ) {
- *out++ = *in++;
- }
- *out = 0;
-}
-
-
-/*
-==================
-Com_DefaultExtension
-==================
-*/
-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 );
-}
-
-/*
-============================================================================
-
- BYTE ORDER FUNCTIONS
-
-============================================================================
-*/
-
-// can't just use function pointers, or dll linkage can
-// mess up when qcommon is included in multiple places
-static short (*_BigShort) (short l);
-static short (*_LittleShort) (short l);
-static int (*_BigLong) (int l);
-static int (*_LittleLong) (int l);
-static float (*_BigFloat) (float l);
-static float (*_LittleFloat) (float l);
-
-short BigShort(short l){return _BigShort(l);}
-short LittleShort(short l) {return _LittleShort(l);}
-int BigLong (int l) {return _BigLong(l);}
-int LittleLong (int l) {return _LittleLong(l);}
-float BigFloat (float l) {return _BigFloat(l);}
-float LittleFloat (float l) {return _LittleFloat(l);}
-
-short ShortSwap (short l)
-{
- byte b1,b2;
-
- b1 = l&255;
- b2 = (l>>8)&255;
-
- return (b1<<8) + b2;
-}
-
-short ShortNoSwap (short l)
-{
- return l;
-}
-
-int LongSwap (int l)
-{
- byte b1,b2,b3,b4;
-
- 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;
-}
-
-int LongNoSwap (int l)
-{
- return l;
-}
-
-float FloatSwap (float f)
-{
- union
- {
- float f;
- byte b[4];
- } 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;
-}
-
-/*
-================
-Swap_Init
-================
-*/
-void Swap_Init (void)
-{
- byte swaptest[2] = {1,0};
-
-// set the byte swapping variables in a portable manner
- if ( *(short *)swaptest == 1)
- {
- _BigShort = ShortSwap;
- _LittleShort = ShortNoSwap;
- _BigLong = LongSwap;
- _LittleLong = LongNoSwap;
- _BigFloat = FloatSwap;
- _LittleFloat = FloatNoSwap;
- }
- else
- {
- _BigShort = ShortNoSwap;
- _LittleShort = ShortSwap;
- _BigLong = LongNoSwap;
- _LittleLong = LongSwap;
- _BigFloat = FloatNoSwap;
- _LittleFloat = FloatSwap;
- }
-
-}
-
-/*
-===============
-Com_ParseInfos
-===============
-*/
-int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
- const 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_Parse( &buf );
- if ( !token[0] ) {
- Com_Printf( "Unexpected end of info file\n" );
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- Q_strncpyz( key, token, sizeof( key ) );
-
- token = Com_ParseOnLine( &buf );
- if ( !token[0] ) {
- token = "<NULL>";
- }
- Info_SetValueForKey( infos[count], key, token );
- }
- count++;
- }
-
- return count;
-}
-
-
-
-/*
-============================================================================
-
- LIBRARY REPLACEMENT FUNCTIONS
-
-============================================================================
-*/
-
-int Q_isprint( int c )
-{
- if ( c >= 0x20 && c <= 0x7E )
- return ( 1 );
- return ( 0 );
-}
-
-int Q_islower( int c )
-{
- if (c >= 'a' && c <= 'z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isupper( int c )
-{
- if (c >= 'A' && c <= 'Z')
- return ( 1 );
- return ( 0 );
-}
-
-int Q_isalpha( int c )
-{
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
- return ( 1 );
- return ( 0 );
-}
-
-char* Q_strrchr( const char* string, int c )
-{
- char cc = c;
- char *s;
- char *sp=(char *)0;
-
- s = (char*)string;
-
- while (*s)
- {
- if (*s == cc)
- sp = s;
- s++;
- }
- if (cc == 0)
- sp = s;
-
- return sp;
-}
-
-/*
-=============
-Q_strncpyz
-
-Safe strncpy that ensures a trailing zero
-=============
-*/
-void Q_strncpyz( char *dest, const char *src, int destsize ) {
- if ( !src ) {
- Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
- }
- if ( destsize < 1 ) {
- Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
- }
-
- strncpy( dest, src, destsize-1 );
- dest[destsize-1] = 0;
-}
-
-int Q_stricmpn (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- if (c1 >= 'a' && c1 <= 'z') {
- c1 -= ('a' - 'A');
- }
- if (c2 >= 'a' && c2 <= 'z') {
- c2 -= ('a' - 'A');
- }
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_strncmp (const char *s1, const char *s2, int n) {
- int c1, c2;
-
- do {
- c1 = *s1++;
- c2 = *s2++;
-
- if (!n--) {
- return 0; // strings are equal until end point
- }
-
- if (c1 != c2) {
- return c1 < c2 ? -1 : 1;
- }
- } while (c1);
-
- return 0; // strings are equal
-}
-
-int Q_stricmp (const char *s1, const char *s2) {
- return Q_stricmpn (s1, s2, 99999);
-}
-
-
-char *Q_strlwr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = tolower(*s);
- s++;
- }
- return s1;
-}
-
-char *Q_strupr( char *s1 ) {
- char *s;
-
- s = s1;
- while ( *s ) {
- *s = toupper(*s);
- s++;
- }
- return s1;
-}
-
-
-// never goes past bounds or leaves without a terminating 0
-void Q_strcat( char *dest, int size, const char *src ) {
- int l1;
-
- l1 = strlen( dest );
- if ( l1 >= size ) {
- Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
- }
- Q_strncpyz( dest + l1, src, size - l1 );
-}
-
-
-int Q_PrintStrlen( const char *string ) {
- int len;
- const char *p;
-
- if( !string ) {
- return 0;
- }
-
- len = 0;
- p = string;
- while( *p ) {
- if( Q_IsColorString( p ) ) {
- p += 2;
- continue;
- }
- p++;
- len++;
- }
-
- return len;
-}
-
-
-char *Q_CleanStr( char *string ) {
- char* d;
- char* s;
- int c;
-
- s = string;
- d = string;
- while ((c = *s) != 0 ) {
- if ( Q_IsColorString( s ) ) {
- s++;
- }
- else if ( c >= 0x20 && c <= 0x7E ) {
- *d++ = c;
- }
- s++;
- }
- *d = '\0';
-
- return string;
-}
-
-
-void 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);
- 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);
- }
- Q_strncpyz (dest, bigbuffer, size );
-}
-
-
-/*
-============
-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, ... ) {
- va_list argptr;
- 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);
- va_end (argptr);
-
- return buf;
-}
-
-
-/*
-=====================================================================
-
- INFO STRINGS
-
-=====================================================================
-*/
-
-/*
-===============
-Info_ValueForKey
-
-Searches the string for the given
-key and returns the associated value, or an empty string.
-FIXME: overflow check?
-===============
-*/
-char *Info_ValueForKey( const char *s, const char *key ) {
- char pkey[MAX_INFO_KEY];
- static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
- // work without stomping on each other
- static int valueindex = 0;
- char *o;
-
- if ( !s || !key ) {
- return "";
- }
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
- }
-
- valueindex ^= 1;
- if (*s == '\\')
- s++;
- while (1)
- {
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return "";
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value[valueindex];
-
- while (*s != '\\' && *s)
- {
- *o++ = *s++;
- }
- *o = 0;
-
- if (!Q_stricmp (key, pkey) )
- return value[valueindex];
-
- if (!*s)
- break;
- s++;
- }
-
- return "";
-}
-
-
-/*
-===================
-Info_NextPair
-
-Used to itterate through all the key/value pairs in an info string
-===================
-*/
-void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
- char *o;
- const char *s;
-
- s = *head;
-
- if ( *s == '\\' ) {
- s++;
- }
- key[0] = 0;
- value[0] = 0;
-
- o = key;
- while ( *s != '\\' ) {
- if ( !*s ) {
- *o = 0;
- *head = s;
- return;
- }
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while ( *s != '\\' && *s ) {
- *o++ = *s++;
- }
- *o = 0;
-
- *head = s;
-}
-
-
-/*
-===================
-Info_RemoveKey
-===================
-*/
-void Info_RemoveKey( char *s, const char *key ) {
- char *start;
- char pkey[MAX_INFO_KEY];
- char value[MAX_INFO_VALUE];
- char *o;
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
- }
-
- if (strchr (key, '\\')) {
- return;
- }
-
- while (1)
- {
- start = s;
- if (*s == '\\')
- s++;
- o = pkey;
- while (*s != '\\')
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
- s++;
-
- o = value;
- while (*s != '\\' && *s)
- {
- if (!*s)
- return;
- *o++ = *s++;
- }
- *o = 0;
-
- if (!strcmp (key, pkey) )
- {
- strcpy (start, s); // remove this part
- return;
- }
-
- if (!*s)
- return;
- }
-
-}
-
-
-/*
-==================
-Info_Validate
-
-Some characters are illegal in info strings because they
-can mess up the server's parsing
-==================
-*/
-qboolean Info_Validate( const char *s ) {
- if ( strchr( s, '\"' ) ) {
- return qfalse;
- }
- if ( strchr( s, ';' ) ) {
- return qfalse;
- }
- return qtrue;
-}
-
-/*
-==================
-Info_SetValueForKey
-
-Changes or adds a key/value pair
-==================
-*/
-void Info_SetValueForKey( char *s, const char *key, const char *value ) {
- char newi[MAX_INFO_STRING];
-
- if ( strlen( s ) >= MAX_INFO_STRING ) {
- Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
- }
-
- if (strchr (key, '\\') || strchr (value, '\\'))
- {
- Com_Printf ("Can't use keys or values with a \\\n");
- return;
- }
-
- if (strchr (key, ';') || strchr (value, ';'))
- {
- Com_Printf ("Can't use keys or values with a semicolon\n");
- return;
- }
-
- if (strchr (key, '\"') || strchr (value, '\"'))
- {
- Com_Printf ("Can't use keys or values with a \"\n");
- return;
- }
-
- Info_RemoveKey (s, key);
- if (!value || !strlen(value))
- return;
-
- Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
-
- if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
- {
- Com_Printf ("Info string length exceeded\n");
- return;
- }
-
- strcat (s, newi);
-}
-
-//====================================================================
-
-
-/*
-===============
-ParseHex
-===============
-*/
-int ParseHex( const char *text ) {
- int value;
- int c;
-
- value = 0;
- while ( ( c = *text++ ) != 0 ) {
- if ( c >= '0' && c <= '9' ) {
- value = value * 16 + c - '0';
- continue;
- }
- if ( c >= 'a' && c <= 'f' ) {
- value = value * 16 + 10 + c - 'a';
- continue;
- }
- if ( c >= 'A' && c <= 'F' ) {
- value = value * 16 + 10 + c - 'A';
- continue;
- }
- }
-
- return value;
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// q_shared.c -- stateless support routines that are included in each code dll
+#include "q_shared.hpp"
+
+/*
+============================================================================
+
+GROWLISTS
+
+============================================================================
+*/
+
+// malloc / free all in one place for debugging
+extern "C" void *Com_Allocate( int bytes );
+extern "C" void Com_Dealloc( void *ptr );
+
+void Com_InitGrowList( growList_t *list, int maxElements ) {
+ list->maxElements = maxElements;
+ list->currentElements = 0;
+ list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
+}
+
+int Com_AddToGrowList( growList_t *list, void *data ) {
+ void **old;
+
+ if ( list->currentElements != list->maxElements ) {
+ list->elements[list->currentElements] = data;
+ return list->currentElements++;
+ }
+
+ // grow, reallocate and move
+ old = list->elements;
+
+ if ( list->maxElements < 0 ) {
+ Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
+ }
+
+ if ( list->maxElements == 0 ) {
+ // initialize the list to hold 100 elements
+ Com_InitGrowList( list, 100 );
+ return Com_AddToGrowList( list, data );
+ }
+
+ list->maxElements *= 2;
+
+ Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
+
+ list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
+
+ if ( !list->elements ) {
+ Com_Error( ERR_DROP, "Growlist alloc failed" );
+ }
+
+ memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
+
+ Com_Dealloc( old );
+
+ return Com_AddToGrowList( list, data );
+}
+
+void *Com_GrowListElement( const growList_t *list, int index ) {
+ if ( index < 0 || index >= list->currentElements ) {
+ Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
+ index, list->currentElements );
+ }
+ return list->elements[index];
+}
+
+int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
+ int i;
+
+ for ( i = 0 ; i < list->currentElements ; i++ ) {
+ if ( list->elements[i] == element ) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//============================================================================
+
+
+float Com_Clamp( float min, float max, float value ) {
+ if ( value < min ) {
+ return min;
+ }
+ if ( value > max ) {
+ return max;
+ }
+ return value;
+}
+
+/*
+============
+Com_StringContains
+============
+*/
+const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
+ int len, i, j;
+
+ len = strlen(str1) - strlen(str2);
+ for (i = 0; i <= len; i++, str1++) {
+ for (j = 0; str2[j]; j++) {
+ if (casesensitive) {
+ if (str1[j] != str2[j]) {
+ break;
+ }
+ }
+ else {
+ if (toupper(str1[j]) != toupper(str2[j])) {
+ break;
+ }
+ }
+ }
+ if (!str2[j]) {
+ return str1;
+ }
+ }
+ return NULL;
+}
+
+/*
+============
+Com_Filter
+============
+*/
+int Com_Filter( const char *filter, const char *name, int casesensitive)
+{
+ char buf[MAX_TOKEN_CHARS];
+ const char *ptr;
+ int i, found;
+
+ while(*filter) {
+ if (*filter == '*') {
+ filter++;
+ for (i = 0; *filter; i++) {
+ if (*filter == '*' || *filter == '?') break;
+ buf[i] = *filter;
+ filter++;
+ }
+ buf[i] = '\0';
+ if (strlen(buf)) {
+ ptr = Com_StringContains(name, buf, casesensitive);
+ if (!ptr) return qfalse;
+ name = ptr + strlen(buf);
+ }
+ }
+ else if (*filter == '?') {
+ filter++;
+ name++;
+ }
+ else if (*filter == '[' && *(filter+1) == '[') {
+ filter++;
+ }
+ else if (*filter == '[') {
+ filter++;
+ found = qfalse;
+ while(*filter && !found) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
+ if (casesensitive) {
+ if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
+ }
+ else {
+ if (toupper(*name) >= toupper(*filter) &&
+ toupper(*name) <= toupper(*(filter+2))) found = qtrue;
+ }
+ filter += 3;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter == *name) found = qtrue;
+ }
+ else {
+ if (toupper(*filter) == toupper(*name)) found = qtrue;
+ }
+ filter++;
+ }
+ }
+ if (!found) return qfalse;
+ while(*filter) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ filter++;
+ }
+ filter++;
+ name++;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter != *name) return qfalse;
+ }
+ else {
+ if (toupper(*filter) != toupper(*name)) return qfalse;
+ }
+ filter++;
+ name++;
+ }
+ }
+ return qtrue;
+}
+
+
+/*
+================
+Com_HashString
+
+================
+*/
+int Com_HashString( const char *fname ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash &= (FILE_HASH_SIZE-1);
+ return hash;
+}
+
+
+/*
+============
+Com_SkipPath
+============
+*/
+char *Com_SkipPath (char *pathname)
+{
+ char *last;
+
+ last = pathname;
+ while (*pathname)
+ {
+ if (*pathname=='/')
+ last = pathname+1;
+ pathname++;
+ }
+ return last;
+}
+
+/*
+============
+Com_StripExtension
+============
+*/
+void Com_StripExtension( const char *in, char *out ) {
+ while ( *in && *in != '.' ) {
+ *out++ = *in++;
+ }
+ *out = 0;
+}
+
+
+/*
+==================
+Com_DefaultExtension
+==================
+*/
+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 );
+}
+
+/*
+============================================================================
+
+ BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+// can't just use function pointers, or dll linkage can
+// mess up when qcommon is included in multiple places
+static short (*_BigShort) (short l);
+static short (*_LittleShort) (short l);
+static int (*_BigLong) (int l);
+static int (*_LittleLong) (int l);
+static float (*_BigFloat) (float l);
+static float (*_LittleFloat) (float l);
+
+short BigShort(short l){return _BigShort(l);}
+short LittleShort(short l) {return _LittleShort(l);}
+int BigLong (int l) {return _BigLong(l);}
+int LittleLong (int l) {return _LittleLong(l);}
+float BigFloat (float l) {return _BigFloat(l);}
+float LittleFloat (float l) {return _LittleFloat(l);}
+
+short ShortSwap (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short ShortNoSwap (short l)
+{
+ return l;
+}
+
+int LongSwap (int l)
+{
+ byte b1,b2,b3,b4;
+
+ 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;
+}
+
+int LongNoSwap (int l)
+{
+ return l;
+}
+
+float FloatSwap (float f)
+{
+ union
+ {
+ float f;
+ byte b[4];
+ } 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;
+}
+
+/*
+================
+Swap_Init
+================
+*/
+void Swap_Init (void)
+{
+ byte swaptest[2] = {1,0};
+
+// set the byte swapping variables in a portable manner
+ if ( *(short *)swaptest == 1)
+ {
+ _BigShort = ShortSwap;
+ _LittleShort = ShortNoSwap;
+ _BigLong = LongSwap;
+ _LittleLong = LongNoSwap;
+ _BigFloat = FloatSwap;
+ _LittleFloat = FloatNoSwap;
+ }
+ else
+ {
+ _BigShort = ShortNoSwap;
+ _LittleShort = ShortSwap;
+ _BigLong = LongNoSwap;
+ _LittleLong = LongSwap;
+ _BigFloat = FloatNoSwap;
+ _LittleFloat = FloatSwap;
+ }
+
+}
+
+/*
+===============
+Com_ParseInfos
+===============
+*/
+int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
+ const 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_Parse( &buf );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = Com_ParseOnLine( &buf );
+ if ( !token[0] ) {
+ token = "<NULL>";
+ }
+ Info_SetValueForKey( infos[count], key, token );
+ }
+ count++;
+ }
+
+ return count;
+}
+
+
+
+/*
+============================================================================
+
+ LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+int Q_isprint( int c )
+{
+ if ( c >= 0x20 && c <= 0x7E )
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_islower( int c )
+{
+ if (c >= 'a' && c <= 'z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isupper( int c )
+{
+ if (c >= 'A' && c <= 'Z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isalpha( int c )
+{
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ return ( 1 );
+ return ( 0 );
+}
+
+char* Q_strrchr( const char* string, int c )
+{
+ char cc = c;
+ char *s;
+ char *sp=(char *)0;
+
+ s = (char*)string;
+
+ while (*s)
+ {
+ if (*s == cc)
+ sp = s;
+ s++;
+ }
+ if (cc == 0)
+ sp = s;
+
+ return sp;
+}
+
+/*
+=============
+Q_strncpyz
+
+Safe strncpy that ensures a trailing zero
+=============
+*/
+void Q_strncpyz( char *dest, const char *src, int destsize ) {
+ if ( !src ) {
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
+ }
+ if ( destsize < 1 ) {
+ Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
+ }
+
+ strncpy( dest, src, destsize-1 );
+ dest[destsize-1] = 0;
+}
+
+int Q_stricmpn (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ if (c1 >= 'a' && c1 <= 'z') {
+ c1 -= ('a' - 'A');
+ }
+ if (c2 >= 'a' && c2 <= 'z') {
+ c2 -= ('a' - 'A');
+ }
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_strncmp (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_stricmp (const char *s1, const char *s2) {
+ return Q_stricmpn (s1, s2, 99999);
+}
+
+
+char *Q_strlwr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = tolower(*s);
+ s++;
+ }
+ return s1;
+}
+
+char *Q_strupr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = toupper(*s);
+ s++;
+ }
+ return s1;
+}
+
+
+// never goes past bounds or leaves without a terminating 0
+void Q_strcat( char *dest, int size, const char *src ) {
+ int l1;
+
+ l1 = strlen( dest );
+ if ( l1 >= size ) {
+ Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
+ }
+ Q_strncpyz( dest + l1, src, size - l1 );
+}
+
+
+int Q_PrintStrlen( const char *string ) {
+ int len;
+ const char *p;
+
+ if( !string ) {
+ return 0;
+ }
+
+ len = 0;
+ p = string;
+ while( *p ) {
+ if( Q_IsColorString( p ) ) {
+ p += 2;
+ continue;
+ }
+ p++;
+ len++;
+ }
+
+ return len;
+}
+
+
+char *Q_CleanStr( char *string ) {
+ char* d;
+ char* s;
+ int c;
+
+ s = string;
+ d = string;
+ while ((c = *s) != 0 ) {
+ if ( Q_IsColorString( s ) ) {
+ s++;
+ }
+ else if ( c >= 0x20 && c <= 0x7E ) {
+ *d++ = c;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return string;
+}
+
+
+void 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);
+ 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);
+ }
+ Q_strncpyz (dest, bigbuffer, size );
+}
+
+
+/*
+============
+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, ... ) {
+ va_list argptr;
+ 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);
+ va_end (argptr);
+
+ return buf;
+}
+
+
+/*
+=====================================================================
+
+ INFO STRINGS
+
+=====================================================================
+*/
+
+/*
+===============
+Info_ValueForKey
+
+Searches the string for the given
+key and returns the associated value, or an empty string.
+FIXME: overflow check?
+===============
+*/
+char *Info_ValueForKey( const char *s, const char *key ) {
+ char pkey[MAX_INFO_KEY];
+ static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
+ // work without stomping on each other
+ static int valueindex = 0;
+ char *o;
+
+ if ( !s || !key ) {
+ return "";
+ }
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
+ }
+
+ valueindex ^= 1;
+ if (*s == '\\')
+ s++;
+ while (1)
+ {
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return "";
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value[valueindex];
+
+ while (*s != '\\' && *s)
+ {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!Q_stricmp (key, pkey) )
+ return value[valueindex];
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ return "";
+}
+
+
+/*
+===================
+Info_NextPair
+
+Used to itterate through all the key/value pairs in an info string
+===================
+*/
+void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
+ char *o;
+ const char *s;
+
+ s = *head;
+
+ if ( *s == '\\' ) {
+ s++;
+ }
+ key[0] = 0;
+ value[0] = 0;
+
+ o = key;
+ while ( *s != '\\' ) {
+ if ( !*s ) {
+ *o = 0;
+ *head = s;
+ return;
+ }
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while ( *s != '\\' && *s ) {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ *head = s;
+}
+
+
+/*
+===================
+Info_RemoveKey
+===================
+*/
+void Info_RemoveKey( char *s, const char *key ) {
+ char *start;
+ char pkey[MAX_INFO_KEY];
+ char value[MAX_INFO_VALUE];
+ char *o;
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
+ }
+
+ if (strchr (key, '\\')) {
+ return;
+ }
+
+ while (1)
+ {
+ start = s;
+ if (*s == '\\')
+ s++;
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while (*s != '\\' && *s)
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!strcmp (key, pkey) )
+ {
+ strcpy (start, s); // remove this part
+ return;
+ }
+
+ if (!*s)
+ return;
+ }
+
+}
+
+
+/*
+==================
+Info_Validate
+
+Some characters are illegal in info strings because they
+can mess up the server's parsing
+==================
+*/
+qboolean Info_Validate( const char *s ) {
+ if ( strchr( s, '\"' ) ) {
+ return qfalse;
+ }
+ if ( strchr( s, ';' ) ) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==================
+Info_SetValueForKey
+
+Changes or adds a key/value pair
+==================
+*/
+void Info_SetValueForKey( char *s, const char *key, const char *value ) {
+ char newi[MAX_INFO_STRING];
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
+ }
+
+ if (strchr (key, '\\') || strchr (value, '\\'))
+ {
+ Com_Printf ("Can't use keys or values with a \\\n");
+ return;
+ }
+
+ if (strchr (key, ';') || strchr (value, ';'))
+ {
+ Com_Printf ("Can't use keys or values with a semicolon\n");
+ return;
+ }
+
+ if (strchr (key, '\"') || strchr (value, '\"'))
+ {
+ Com_Printf ("Can't use keys or values with a \"\n");
+ return;
+ }
+
+ Info_RemoveKey (s, key);
+ if (!value || !strlen(value))
+ return;
+
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+ if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
+ {
+ Com_Printf ("Info string length exceeded\n");
+ return;
+ }
+
+ strcat (s, newi);
+}
+
+//====================================================================
+
+
+/*
+===============
+ParseHex
+===============
+*/
+int ParseHex( const char *text ) {
+ int value;
+ int c;
+
+ value = 0;
+ while ( ( c = *text++ ) != 0 ) {
+ if ( c >= '0' && c <= '9' ) {
+ value = value * 16 + c - '0';
+ continue;
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ value = value * 16 + 10 + c - 'a';
+ continue;
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ value = value * 16 + 10 + c - 'A';
+ continue;
+ }
+ }
+
+ return value;
+}