diff options
Diffstat (limited to 'code/splines/q_shared.cpp')
-rwxr-xr-x | code/splines/q_shared.cpp | 1952 |
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; +} |