2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 // q_shared.c -- stateless support routines that are included in each code dll
26 ============================================================================
30 ============================================================================
33 // malloc / free all in one place for debugging
34 extern "C" void *Com_Allocate( int bytes );
35 extern "C" void Com_Dealloc( void *ptr );
37 void Com_InitGrowList( growList_t *list, int maxElements ) {
38 list->maxElements = maxElements;
39 list->currentElements = 0;
40 list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
43 int Com_AddToGrowList( growList_t *list, void *data ) {
46 if ( list->currentElements != list->maxElements ) {
47 list->elements[list->currentElements] = data;
48 return list->currentElements++;
51 // grow, reallocate and move
54 if ( list->maxElements < 0 ) {
55 Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
58 if ( list->maxElements == 0 ) {
59 // initialize the list to hold 100 elements
60 Com_InitGrowList( list, 100 );
61 return Com_AddToGrowList( list, data );
64 list->maxElements *= 2;
66 Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
68 list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
70 if ( !list->elements ) {
71 Com_Error( ERR_DROP, "Growlist alloc failed" );
74 memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
78 return Com_AddToGrowList( list, data );
81 void *Com_GrowListElement( const growList_t *list, int index ) {
82 if ( index < 0 || index >= list->currentElements ) {
83 Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
84 index, list->currentElements );
86 return list->elements[index];
89 int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
92 for ( i = 0 ; i < list->currentElements ; i++ ) {
93 if ( list->elements[i] == element ) {
100 //============================================================================
103 float Com_Clamp( float min, float max, float value ) {
118 const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
121 len = strlen(str1) - strlen(str2);
122 for (i = 0; i <= len; i++, str1++) {
123 for (j = 0; str2[j]; j++) {
125 if (str1[j] != str2[j]) {
130 if (toupper(str1[j]) != toupper(str2[j])) {
147 int Com_Filter( const char *filter, const char *name, int casesensitive)
149 char buf[MAX_TOKEN_CHARS];
154 if (*filter == '*') {
156 for (i = 0; *filter; i++) {
157 if (*filter == '*' || *filter == '?') break;
163 ptr = Com_StringContains(name, buf, casesensitive);
164 if (!ptr) return qfalse;
165 name = ptr + strlen(buf);
168 else if (*filter == '?') {
172 else if (*filter == '[' && *(filter+1) == '[') {
175 else if (*filter == '[') {
178 while(*filter && !found) {
179 if (*filter == ']' && *(filter+1) != ']') break;
180 if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
182 if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
185 if (toupper(*name) >= toupper(*filter) &&
186 toupper(*name) <= toupper(*(filter+2))) found = qtrue;
192 if (*filter == *name) found = qtrue;
195 if (toupper(*filter) == toupper(*name)) found = qtrue;
200 if (!found) return qfalse;
202 if (*filter == ']' && *(filter+1) != ']') break;
210 if (*filter != *name) return qfalse;
213 if (toupper(*filter) != toupper(*name)) return qfalse;
229 int Com_HashString( const char *fname ) {
236 while (fname[i] != '\0') {
237 letter = tolower(fname[i]);
238 if (letter =='.') break; // don't include extension
239 if (letter =='\\') letter = '/'; // damn path names
240 hash+=(long)(letter)*(i+119);
243 hash &= (FILE_HASH_SIZE-1);
253 char *Com_SkipPath (char *pathname)
272 void Com_StripExtension( const char *in, char *out ) {
273 while ( *in && *in != '.' ) {
285 void Com_DefaultExtension (char *path, int maxSize, const char *extension ) {
286 char oldPath[MAX_QPATH];
290 // if path doesn't have a .EXT, append extension
291 // (extension should include the .)
293 src = path + strlen(path) - 1;
295 while (*src != '/' && src != path) {
297 return; // it has an extension
302 Q_strncpyz( oldPath, path, sizeof( oldPath ) );
303 Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
307 ============================================================================
311 ============================================================================
314 // can't just use function pointers, or dll linkage can
315 // mess up when qcommon is included in multiple places
316 static short (*_BigShort) (short l);
317 static short (*_LittleShort) (short l);
318 static int (*_BigLong) (int l);
319 static int (*_LittleLong) (int l);
320 static float (*_BigFloat) (float l);
321 static float (*_LittleFloat) (float l);
323 short BigShort(short l){return _BigShort(l);}
324 short LittleShort(short l) {return _LittleShort(l);}
325 int BigLong (int l) {return _BigLong(l);}
326 int LittleLong (int l) {return _LittleLong(l);}
327 float BigFloat (float l) {return _BigFloat(l);}
328 float LittleFloat (float l) {return _LittleFloat(l);}
330 short ShortSwap (short l)
340 short ShortNoSwap (short l)
354 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
357 int LongNoSwap (int l)
362 float FloatSwap (float f)
372 dat2.b[0] = dat1.b[3];
373 dat2.b[1] = dat1.b[2];
374 dat2.b[2] = dat1.b[1];
375 dat2.b[3] = dat1.b[0];
379 float FloatNoSwap (float f)
389 void Swap_Init (void)
391 byte swaptest[2] = {1,0};
393 // set the byte swapping variables in a portable manner
394 if ( *(short *)swaptest == 1)
396 _BigShort = ShortSwap;
397 _LittleShort = ShortNoSwap;
399 _LittleLong = LongNoSwap;
400 _BigFloat = FloatSwap;
401 _LittleFloat = FloatNoSwap;
405 _BigShort = ShortNoSwap;
406 _LittleShort = ShortSwap;
407 _BigLong = LongNoSwap;
408 _LittleLong = LongSwap;
409 _BigFloat = FloatNoSwap;
410 _LittleFloat = FloatSwap;
420 int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
423 char key[MAX_TOKEN_CHARS];
428 token = Com_Parse( &buf );
432 if ( strcmp( token, "{" ) ) {
433 Com_Printf( "Missing { in info file\n" );
437 if ( count == max ) {
438 Com_Printf( "Max infos exceeded\n" );
444 token = Com_Parse( &buf );
446 Com_Printf( "Unexpected end of info file\n" );
449 if ( !strcmp( token, "}" ) ) {
452 Q_strncpyz( key, token, sizeof( key ) );
454 token = Com_ParseOnLine( &buf );
458 Info_SetValueForKey( infos[count], key, token );
469 ============================================================================
471 LIBRARY REPLACEMENT FUNCTIONS
473 ============================================================================
476 int Q_isprint( int c )
478 if ( c >= 0x20 && c <= 0x7E )
483 int Q_islower( int c )
485 if (c >= 'a' && c <= 'z')
490 int Q_isupper( int c )
492 if (c >= 'A' && c <= 'Z')
497 int Q_isalpha( int c )
499 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
504 char* Q_strrchr( const char* string, int c )
528 Safe strncpy that ensures a trailing zero
531 void Q_strncpyz( char *dest, const char *src, int destsize ) {
533 Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
535 if ( destsize < 1 ) {
536 Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
539 strncpy( dest, src, destsize-1 );
540 dest[destsize-1] = 0;
543 int Q_stricmpn (const char *s1, const char *s2, int n) {
551 return 0; // strings are equal until end point
555 if (c1 >= 'a' && c1 <= 'z') {
558 if (c2 >= 'a' && c2 <= 'z') {
562 return c1 < c2 ? -1 : 1;
567 return 0; // strings are equal
570 int Q_strncmp (const char *s1, const char *s2, int n) {
578 return 0; // strings are equal until end point
582 return c1 < c2 ? -1 : 1;
586 return 0; // strings are equal
589 int Q_stricmp (const char *s1, const char *s2) {
590 return Q_stricmpn (s1, s2, 99999);
594 char *Q_strlwr( char *s1 ) {
605 char *Q_strupr( char *s1 ) {
617 // never goes past bounds or leaves without a terminating 0
618 void Q_strcat( char *dest, int size, const char *src ) {
623 Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
625 Q_strncpyz( dest + l1, src, size - l1 );
629 int Q_PrintStrlen( const char *string ) {
640 if( Q_IsColorString( p ) ) {
652 char *Q_CleanStr( char *string ) {
659 while ((c = *s) != 0 ) {
660 if ( Q_IsColorString( s ) ) {
663 else if ( c >= 0x20 && c <= 0x7E ) {
674 void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
677 char bigbuffer[32000]; // big, but small enough to fit in PPC stack
679 va_start (argptr,fmt);
680 len = vsprintf (bigbuffer,fmt,argptr);
682 if ( len >= sizeof( bigbuffer ) ) {
683 Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
686 Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
688 Q_strncpyz (dest, bigbuffer, size );
696 does a varargs printf into a temp buffer, so I don't need to have
697 varargs versions of all text functions.
698 FIXME: make this buffer size safe someday
701 char * QDECL va( char *format, ... ) {
703 static char string[2][32000]; // in case va is called by nested functions
704 static int index = 0;
707 buf = string[index & 1];
710 va_start (argptr, format);
711 vsprintf (buf, format,argptr);
719 =====================================================================
723 =====================================================================
730 Searches the string for the given
731 key and returns the associated value, or an empty string.
732 FIXME: overflow check?
735 char *Info_ValueForKey( const char *s, const char *key ) {
736 char pkey[MAX_INFO_KEY];
737 static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
738 // work without stomping on each other
739 static int valueindex = 0;
746 if ( strlen( s ) >= MAX_INFO_STRING ) {
747 Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
765 o = value[valueindex];
767 while (*s != '\\' && *s)
773 if (!Q_stricmp (key, pkey) )
774 return value[valueindex];
789 Used to itterate through all the key/value pairs in an info string
792 void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
805 while ( *s != '\\' ) {
817 while ( *s != '\\' && *s ) {
831 void Info_RemoveKey( char *s, const char *key ) {
833 char pkey[MAX_INFO_KEY];
834 char value[MAX_INFO_VALUE];
837 if ( strlen( s ) >= MAX_INFO_STRING ) {
838 Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
841 if (strchr (key, '\\')) {
861 while (*s != '\\' && *s)
869 if (!strcmp (key, pkey) )
871 strcpy (start, s); // remove this part
886 Some characters are illegal in info strings because they
887 can mess up the server's parsing
890 qboolean Info_Validate( const char *s ) {
891 if ( strchr( s, '\"' ) ) {
894 if ( strchr( s, ';' ) ) {
904 Changes or adds a key/value pair
907 void Info_SetValueForKey( char *s, const char *key, const char *value ) {
908 char newi[MAX_INFO_STRING];
910 if ( strlen( s ) >= MAX_INFO_STRING ) {
911 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
914 if (strchr (key, '\\') || strchr (value, '\\'))
916 Com_Printf ("Can't use keys or values with a \\\n");
920 if (strchr (key, ';') || strchr (value, ';'))
922 Com_Printf ("Can't use keys or values with a semicolon\n");
926 if (strchr (key, '\"') || strchr (value, '\"'))
928 Com_Printf ("Can't use keys or values with a \"\n");
932 Info_RemoveKey (s, key);
933 if (!value || !strlen(value))
936 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
938 if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
940 Com_Printf ("Info string length exceeded\n");
947 //====================================================================
955 int ParseHex( const char *text ) {
960 while ( ( c = *text++ ) != 0 ) {
961 if ( c >= '0' && c <= '9' ) {
962 value = value * 16 + c - '0';
965 if ( c >= 'a' && c <= 'f' ) {
966 value = value * 16 + 10 + c - 'a';
969 if ( c >= 'A' && c <= 'F' ) {
970 value = value * 16 + 10 + c - 'A';