123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- /*
- ===========================================================================
- 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;
- }
|