codemp/game/q_shared.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // q_shared.c -- stateless support routines that are included in each code dll
00004 #include "q_shared.h"
00005 
00006 /*
00007 -------------------------
00008 GetIDForString 
00009 -------------------------
00010 */
00011 
00012 
00013 int GetIDForString ( stringID_table_t *table, const char *string )
00014 {
00015         int     index = 0;
00016 
00017         while ( ( table[index].name != NULL ) &&
00018                         ( table[index].name[0] != 0 ) )
00019         {
00020                 if ( !Q_stricmp( table[index].name, string ) )
00021                         return table[index].id;
00022 
00023                 index++;
00024         }
00025 
00026         return -1;
00027 }
00028 
00029 /*
00030 -------------------------
00031 GetStringForID
00032 -------------------------
00033 */
00034 
00035 const char *GetStringForID( stringID_table_t *table, int id )
00036 {
00037         int     index = 0;
00038 
00039         while ( ( table[index].name != NULL ) &&
00040                         ( table[index].name[0] != 0 ) )
00041         {
00042                 if ( table[index].id == id )
00043                         return table[index].name;
00044 
00045                 index++;
00046         }
00047 
00048         return NULL;
00049 }
00050 
00051 int Com_Clampi( int min, int max, int value ) 
00052 {
00053         if ( value < min ) 
00054         {
00055                 return min;
00056         }
00057         if ( value > max ) 
00058         {
00059                 return max;
00060         }
00061         return value;
00062 }
00063 
00064 float Com_Clamp( float min, float max, float value ) {
00065         if ( value < min ) {
00066                 return min;
00067         }
00068         if ( value > max ) {
00069                 return max;
00070         }
00071         return value;
00072 }
00073 
00074 
00075 /*
00076 ============
00077 COM_SkipPath
00078 ============
00079 */
00080 char *COM_SkipPath (char *pathname)
00081 {
00082         char    *last;
00083         
00084         last = pathname;
00085         while (*pathname)
00086         {
00087                 if (*pathname=='/')
00088                         last = pathname+1;
00089                 pathname++;
00090         }
00091         return last;
00092 }
00093 
00094 /*
00095 ============
00096 COM_StripExtension
00097 ============
00098 */
00099 void COM_StripExtension( const char *in, char *out ) {
00100         while ( *in && *in != '.' ) {
00101                 *out++ = *in++;
00102         }
00103         *out = 0;
00104 }
00105 
00106 
00107 /*
00108 ==================
00109 COM_DefaultExtension
00110 ==================
00111 */
00112 void COM_DefaultExtension (char *path, int maxSize, const char *extension ) {
00113         char    oldPath[MAX_QPATH];
00114         char    *src;
00115 
00116 //
00117 // if path doesn't have a .EXT, append extension
00118 // (extension should include the .)
00119 //
00120         src = path + strlen(path) - 1;
00121 
00122         while (*src != '/' && src != path) {
00123                 if ( *src == '.' ) {
00124                         return;                 // it has an extension
00125                 }
00126                 src--;
00127         }
00128 
00129         Q_strncpyz( oldPath, path, sizeof( oldPath ) );
00130         Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
00131 }
00132 
00133 /*
00134 ============================================================================
00135 
00136                                         BYTE ORDER FUNCTIONS
00137 
00138 ============================================================================
00139 */
00140 /*
00141 // can't just use function pointers, or dll linkage can
00142 // mess up when qcommon is included in multiple places
00143 static short    (*_BigShort) (short l);
00144 static short    (*_LittleShort) (short l);
00145 static int              (*_BigLong) (int l);
00146 static int              (*_LittleLong) (int l);
00147 static qint64   (*_BigLong64) (qint64 l);
00148 static qint64   (*_LittleLong64) (qint64 l);
00149 static float    (*_BigFloat) (const float *l);
00150 static float    (*_LittleFloat) (const float *l);
00151 
00152 short   BigShort(short l){return _BigShort(l);}
00153 short   LittleShort(short l) {return _LittleShort(l);}
00154 int             BigLong (int l) {return _BigLong(l);}
00155 int             LittleLong (int l) {return _LittleLong(l);}
00156 qint64  BigLong64 (qint64 l) {return _BigLong64(l);}
00157 qint64  LittleLong64 (qint64 l) {return _LittleLong64(l);}
00158 float   BigFloat (const float *l) {return _BigFloat(l);}
00159 float   LittleFloat (const float *l) {return _LittleFloat(l);}
00160 */
00161 
00162 short   ShortSwap (short l)
00163 {
00164         byte    b1,b2;
00165 
00166         b1 = l&255;
00167         b2 = (l>>8)&255;
00168 
00169         return (b1<<8) + b2;
00170 }
00171 
00172 short   ShortNoSwap (short l)
00173 {
00174         return l;
00175 }
00176 
00177 int    LongSwap (int l)
00178 {
00179         byte    b1,b2,b3,b4;
00180 
00181         b1 = l&255;
00182         b2 = (l>>8)&255;
00183         b3 = (l>>16)&255;
00184         b4 = (l>>24)&255;
00185 
00186         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
00187 }
00188 
00189 int     LongNoSwap (int l)
00190 {
00191         return l;
00192 }
00193 
00194 qint64 Long64Swap (qint64 ll)
00195 {
00196         qint64  result;
00197 
00198         result.b0 = ll.b7;
00199         result.b1 = ll.b6;
00200         result.b2 = ll.b5;
00201         result.b3 = ll.b4;
00202         result.b4 = ll.b3;
00203         result.b5 = ll.b2;
00204         result.b6 = ll.b1;
00205         result.b7 = ll.b0;
00206 
00207         return result;
00208 }
00209 
00210 qint64 Long64NoSwap (qint64 ll)
00211 {
00212         return ll;
00213 }
00214 
00215 typedef union {
00216     float       f;
00217     unsigned int i;
00218 } _FloatByteUnion;
00219 
00220 float FloatSwap (const float *f) {
00221         const _FloatByteUnion *in;
00222         _FloatByteUnion out;
00223 
00224         in = (_FloatByteUnion *)f;
00225         out.i = LongSwap(in->i);
00226 
00227         return out.f;
00228 }
00229 
00230 float FloatNoSwap (const float *f)
00231 {
00232         return *f;
00233 }
00234 
00235 /*
00236 ================
00237 Swap_Init
00238 ================
00239 */
00240 /*
00241 void Swap_Init (void)
00242 {
00243         byte    swaptest[2] = {1,0};
00244 
00245 // set the byte swapping variables in a portable manner 
00246         if ( *(short *)swaptest == 1)
00247         {
00248                 _BigShort = ShortSwap;
00249                 _LittleShort = ShortNoSwap;
00250                 _BigLong = LongSwap;
00251                 _LittleLong = LongNoSwap;
00252                 _BigLong64 = Long64Swap;
00253                 _LittleLong64 = Long64NoSwap;
00254                 _BigFloat = FloatSwap;
00255                 _LittleFloat = FloatNoSwap;
00256         }
00257         else
00258         {
00259                 _BigShort = ShortNoSwap;
00260                 _LittleShort = ShortSwap;
00261                 _BigLong = LongNoSwap;
00262                 _LittleLong = LongSwap;
00263                 _BigLong64 = Long64NoSwap;
00264                 _LittleLong64 = Long64Swap;
00265                 _BigFloat = FloatNoSwap;
00266                 _LittleFloat = FloatSwap;
00267         }
00268 
00269 }
00270 */
00271 
00272 /*
00273 ============================================================================
00274 
00275 PARSING
00276 
00277 ============================================================================
00278 */
00279 
00280 static  char    com_token[MAX_TOKEN_CHARS];
00281 static  char    com_parsename[MAX_TOKEN_CHARS];
00282 static  int             com_lines;
00283 
00284 void COM_BeginParseSession( const char *name )
00285 {
00286         com_lines = 0;
00287         Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
00288 }
00289 
00290 int COM_GetCurrentParseLine( void )
00291 {
00292         return com_lines;
00293 }
00294 
00295 char *COM_Parse( const char **data_p )
00296 {
00297         return COM_ParseExt( data_p, qtrue );
00298 }
00299 
00300 void COM_ParseError( char *format, ... )
00301 {
00302         va_list argptr;
00303         static char string[4096];
00304 
00305         va_start (argptr, format);
00306         vsprintf (string, format, argptr);
00307         va_end (argptr);
00308 
00309         Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string);
00310 }
00311 
00312 void COM_ParseWarning( char *format, ... )
00313 {
00314         va_list argptr;
00315         static char string[4096];
00316 
00317         va_start (argptr, format);
00318         vsprintf (string, format, argptr);
00319         va_end (argptr);
00320 
00321         Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string);
00322 }
00323 
00324 /*
00325 ==============
00326 COM_Parse
00327 
00328 Parse a token out of a string
00329 Will never return NULL, just empty strings
00330 
00331 If "allowLineBreaks" is qtrue then an empty
00332 string will be returned if the next token is
00333 a newline.
00334 ==============
00335 */
00336 const char *SkipWhitespace( const char *data, qboolean *hasNewLines ) {
00337         int c;
00338 
00339         while( (c = *data) <= ' ') {
00340                 if( !c ) {
00341                         return NULL;
00342                 }
00343                 if( c == '\n' ) {
00344                         com_lines++;
00345                         *hasNewLines = qtrue;
00346                 }
00347                 data++;
00348         }
00349 
00350         return data;
00351 }
00352 
00353 int COM_Compress( char *data_p ) {
00354         char *in, *out;
00355         int c;
00356         qboolean newline = qfalse, whitespace = qfalse;
00357         
00358         in = out = data_p;
00359         if (in) {
00360                 while ((c = *in) != 0) {
00361                         // skip double slash comments
00362                         if ( c == '/' && in[1] == '/' ) {
00363                                 while (*in && *in != '\n') {
00364                                         in++;
00365                                 }
00366                                 // skip /* */ comments
00367                         } else if ( c == '/' && in[1] == '*' ) {
00368                                 while ( *in && ( *in != '*' || in[1] != '/' ) ) 
00369                                         in++;
00370                                 if ( *in ) 
00371                                         in += 2;
00372                                 // record when we hit a newline
00373                         } else if ( c == '\n' || c == '\r' ) {
00374                                 newline = qtrue;
00375                                 in++;
00376                                 // record when we hit whitespace
00377                         } else if ( c == ' ' || c == '\t') {
00378                                 whitespace = qtrue;
00379                                 in++;
00380                                 // an actual token
00381                         } else {
00382                                 // if we have a pending newline, emit it (and it counts as whitespace)
00383                                 if (newline) {
00384                                         *out++ = '\n';
00385                                         newline = qfalse;
00386                                         whitespace = qfalse;
00387                                 } if (whitespace) {
00388                                         *out++ = ' ';
00389                                         whitespace = qfalse;
00390                                 }
00391                                 
00392                                 // copy quoted strings unmolested
00393                                 if (c == '"') {
00394                                         *out++ = c;
00395                                         in++;
00396                                         while (1) {
00397                                                 c = *in;
00398                                                 if (c && c != '"') {
00399                                                         *out++ = c;
00400                                                         in++;
00401                                                 } else {
00402                                                         break;
00403                                                 }
00404                                         }
00405                                         if (c == '"') {
00406                                                 *out++ = c;
00407                                                 in++;
00408                                         }
00409                                 } else {
00410                                         *out = c;
00411                                         out++;
00412                                         in++;
00413                                 }
00414                         }
00415                 }
00416         }
00417         *out = 0;
00418         return out - data_p;
00419 }
00420 
00421 char *COM_ParseExt( const char **data_p, qboolean allowLineBreaks )
00422 {
00423         int c = 0, len;
00424         qboolean hasNewLines = qfalse;
00425         const char *data;
00426 
00427         data = *data_p;
00428         len = 0;
00429         com_token[0] = 0;
00430 
00431         // make sure incoming data is valid
00432         if ( !data )
00433         {
00434                 *data_p = NULL;
00435                 return com_token;
00436         }
00437 
00438         while ( 1 )
00439         {
00440                 // skip whitespace
00441                 data = SkipWhitespace( data, &hasNewLines );
00442                 if ( !data )
00443                 {
00444                         *data_p = NULL;
00445                         return com_token;
00446                 }
00447                 if ( hasNewLines && !allowLineBreaks )
00448                 {
00449                         *data_p = data;
00450                         return com_token;
00451                 }
00452 
00453                 c = *data;
00454 
00455                 // skip double slash comments
00456                 if ( c == '/' && data[1] == '/' )
00457                 {
00458                         data += 2;
00459                         while (*data && *data != '\n') {
00460                                 data++;
00461                         }
00462                 }
00463                 // skip /* */ comments
00464                 else if ( c=='/' && data[1] == '*' ) 
00465                 {
00466                         data += 2;
00467                         while ( *data && ( *data != '*' || data[1] != '/' ) ) 
00468                         {
00469                                 data++;
00470                         }
00471                         if ( *data ) 
00472                         {
00473                                 data += 2;
00474                         }
00475                 }
00476                 else
00477                 {
00478                         break;
00479                 }
00480         }
00481 
00482         // handle quoted strings
00483         if (c == '\"')
00484         {
00485                 data++;
00486                 while (1)
00487                 {
00488                         c = *data++;
00489                         if (c=='\"' || !c)
00490                         {
00491                                 com_token[len] = 0;
00492                                 *data_p = ( char * ) data;
00493                                 return com_token;
00494                         }
00495                         if (len < MAX_TOKEN_CHARS)
00496                         {
00497                                 com_token[len] = c;
00498                                 len++;
00499                         }
00500                 }
00501         }
00502 
00503         // parse a regular word
00504         do
00505         {
00506                 if (len < MAX_TOKEN_CHARS)
00507                 {
00508                         com_token[len] = c;
00509                         len++;
00510                 }
00511                 data++;
00512                 c = *data;
00513                 if ( c == '\n' )
00514                         com_lines++;
00515         } while (c>32);
00516 
00517         if (len == MAX_TOKEN_CHARS)
00518         {
00519 //              Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
00520                 len = 0;
00521         }
00522         com_token[len] = 0;
00523 
00524         *data_p = ( char * ) data;
00525         return com_token;
00526 }
00527 
00528 
00529 #if 0
00530 // no longer used
00531 /*
00532 ===============
00533 COM_ParseInfos
00534 ===============
00535 */
00536 int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
00537         char    *token;
00538         int             count;
00539         char    key[MAX_TOKEN_CHARS];
00540 
00541         count = 0;
00542 
00543         while ( 1 ) {
00544                 token = COM_Parse( &buf );
00545                 if ( !token[0] ) {
00546                         break;
00547                 }
00548                 if ( strcmp( token, "{" ) ) {
00549                         Com_Printf( "Missing { in info file\n" );
00550                         break;
00551                 }
00552 
00553                 if ( count == max ) {
00554                         Com_Printf( "Max infos exceeded\n" );
00555                         break;
00556                 }
00557 
00558                 infos[count][0] = 0;
00559                 while ( 1 ) {
00560                         token = COM_ParseExt( &buf, qtrue );
00561                         if ( !token[0] ) {
00562                                 Com_Printf( "Unexpected end of info file\n" );
00563                                 break;
00564                         }
00565                         if ( !strcmp( token, "}" ) ) {
00566                                 break;
00567                         }
00568                         Q_strncpyz( key, token, sizeof( key ) );
00569 
00570                         token = COM_ParseExt( &buf, qfalse );
00571                         if ( !token[0] ) {
00572                                 strcpy( token, "<NULL>" );
00573                         }
00574                         Info_SetValueForKey( infos[count], key, token );
00575                 }
00576                 count++;
00577         }
00578 
00579         return count;
00580 }
00581 #endif
00582 
00583 /*
00584 ===============
00585 COM_ParseString
00586 ===============
00587 */
00588 qboolean COM_ParseString( const char **data, const char **s ) 
00589 {
00590 //      *s = COM_ParseExt( data, qtrue );
00591         *s = COM_ParseExt( data, qfalse );
00592         if ( s[0] == 0 ) 
00593         {
00594                 Com_Printf("unexpected EOF\n");
00595                 return qtrue;
00596         }
00597         return qfalse;
00598 }
00599 
00600 /*
00601 ===============
00602 COM_ParseInt
00603 ===============
00604 */
00605 qboolean COM_ParseInt( const char **data, int *i ) 
00606 {
00607         const char      *token;
00608 
00609         token = COM_ParseExt( data, qfalse );
00610         if ( token[0] == 0 ) 
00611         {
00612                 Com_Printf( "unexpected EOF\n" );
00613                 return qtrue;
00614         }
00615 
00616         *i = atoi( token );
00617         return qfalse;
00618 }
00619 
00620 /*
00621 ===============
00622 COM_ParseFloat
00623 ===============
00624 */
00625 qboolean COM_ParseFloat( const char **data, float *f ) 
00626 {
00627         const char      *token;
00628 
00629         token = COM_ParseExt( data, qfalse );
00630         if ( token[0] == 0 ) 
00631         {
00632                 Com_Printf( "unexpected EOF\n" );
00633                 return qtrue;
00634         }
00635 
00636         *f = atof( token );
00637         return qfalse;
00638 }
00639 
00640 /*
00641 ===============
00642 COM_ParseVec4
00643 ===============
00644 */
00645 qboolean COM_ParseVec4( const char **buffer, vec4_t *c) 
00646 {
00647         int i;
00648         float f;
00649 
00650         for (i = 0; i < 4; i++) 
00651         {
00652                 if (COM_ParseFloat(buffer, &f)) 
00653                 {
00654                         return qtrue;
00655                 }
00656                 (*c)[i] = f;
00657         }
00658         return qfalse;
00659 }
00660 
00661 /*
00662 ==================
00663 COM_MatchToken
00664 ==================
00665 */
00666 void COM_MatchToken( const char **buf_p, char *match ) {
00667         char    *token;
00668 
00669         token = COM_Parse( buf_p );
00670         if ( strcmp( token, match ) ) {
00671                 Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
00672         }
00673 }
00674 
00675 
00676 /*
00677 =================
00678 SkipBracedSection
00679 
00680 The next token should be an open brace.
00681 Skips until a matching close brace is found.
00682 Internal brace depths are properly skipped.
00683 =================
00684 */
00685 void SkipBracedSection (const char **program) {
00686         char                    *token;
00687         int                             depth;
00688 
00689         depth = 0;
00690         do {
00691                 token = COM_ParseExt( program, qtrue );
00692                 if( token[1] == 0 ) {
00693                         if( token[0] == '{' ) {
00694                                 depth++;
00695                         }
00696                         else if( token[0] == '}' ) {
00697                                 depth--;
00698                         }
00699                 }
00700         } while( depth && *program );
00701 }
00702 
00703 /*
00704 =================
00705 SkipRestOfLine
00706 =================
00707 */
00708 void SkipRestOfLine ( const char **data ) {
00709         const char      *p;
00710         int             c;
00711 
00712         p = *data;
00713         while ( (c = *p++) != 0 ) {
00714                 if ( c == '\n' ) {
00715                         com_lines++;
00716                         break;
00717                 }
00718         }
00719 
00720         *data = p;
00721 }
00722 
00723 
00724 void Parse1DMatrix (const char **buf_p, int x, float *m) {
00725         char    *token;
00726         int             i;
00727 
00728         COM_MatchToken( buf_p, "(" );
00729 
00730         for (i = 0 ; i < x ; i++) {
00731                 token = COM_Parse(buf_p);
00732                 m[i] = atof(token);
00733         }
00734 
00735         COM_MatchToken( buf_p, ")" );
00736 }
00737 
00738 void Parse2DMatrix (const char **buf_p, int y, int x, float *m) {
00739         int             i;
00740 
00741         COM_MatchToken( buf_p, "(" );
00742 
00743         for (i = 0 ; i < y ; i++) {
00744                 Parse1DMatrix (buf_p, x, m + i * x);
00745         }
00746 
00747         COM_MatchToken( buf_p, ")" );
00748 }
00749 
00750 void Parse3DMatrix (const char **buf_p, int z, int y, int x, float *m) {
00751         int             i;
00752 
00753         COM_MatchToken( buf_p, "(" );
00754 
00755         for (i = 0 ; i < z ; i++) {
00756                 Parse2DMatrix (buf_p, y, x, m + i * x*y);
00757         }
00758 
00759         COM_MatchToken( buf_p, ")" );
00760 }
00761 
00762 
00763 /*
00764 ============================================================================
00765 
00766                                         LIBRARY REPLACEMENT FUNCTIONS
00767 
00768 ============================================================================
00769 */
00770 
00771 int Q_isprint( int c )
00772 {
00773         if ( c >= 0x20 && c <= 0x7E )
00774                 return ( 1 );
00775         return ( 0 );
00776 }
00777 
00778 int Q_islower( int c )
00779 {
00780         if (c >= 'a' && c <= 'z')
00781                 return ( 1 );
00782         return ( 0 );
00783 }
00784 
00785 int Q_isupper( int c )
00786 {
00787         if (c >= 'A' && c <= 'Z')
00788                 return ( 1 );
00789         return ( 0 );
00790 }
00791 
00792 int Q_isalpha( int c )
00793 {
00794         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
00795                 return ( 1 );
00796         return ( 0 );
00797 }
00798 
00799 char* Q_strrchr( const char* string, int c )
00800 {
00801         char cc = c;
00802         char *s;
00803         char *sp=(char *)0;
00804 
00805         s = (char*)string;
00806 
00807         while (*s)
00808         {
00809                 if (*s == cc)
00810                         sp = s;
00811                 s++;
00812         }
00813         if (cc == 0)
00814                 sp = s;
00815 
00816         return sp;
00817 }
00818 
00819 /*
00820 =============
00821 Q_strncpyz
00822  
00823 Safe strncpy that ensures a trailing zero
00824 =============
00825 */
00826 void Q_strncpyz( char *dest, const char *src, int destsize ) {
00827   // bk001129 - also NULL dest
00828   if ( !dest ) {
00829     Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
00830   }
00831         if ( !src ) {
00832                 Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
00833         }
00834         if ( destsize < 1 ) {
00835                 Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); 
00836         }
00837 
00838         strncpy( dest, src, destsize-1 );
00839   dest[destsize-1] = 0;
00840 }
00841                  
00842 int Q_stricmpn (const char *s1, const char *s2, int n) {
00843         int             c1, c2;
00844 
00845         // bk001129 - moved in 1.17 fix not in id codebase
00846         if ( s1 == NULL ) {
00847            if ( s2 == NULL )
00848              return 0;
00849            else
00850              return -1;
00851         }
00852         else if ( s2==NULL )
00853           return 1;
00854 
00855 
00856         
00857         do {
00858                 c1 = *s1++;
00859                 c2 = *s2++;
00860 
00861                 if (!n--) {
00862                         return 0;               // strings are equal until end point
00863                 }
00864                 
00865                 if (c1 != c2) {
00866                         if (c1 >= 'a' && c1 <= 'z') {
00867                                 c1 -= ('a' - 'A');
00868                         }
00869                         if (c2 >= 'a' && c2 <= 'z') {
00870                                 c2 -= ('a' - 'A');
00871                         }
00872                         if (c1 != c2) {
00873                                 return c1 < c2 ? -1 : 1;
00874                         }
00875                 }
00876         } while (c1);
00877         
00878         return 0;               // strings are equal
00879 }
00880 
00881 int Q_strncmp (const char *s1, const char *s2, int n) {
00882         int             c1, c2;
00883         
00884         do {
00885                 c1 = *s1++;
00886                 c2 = *s2++;
00887 
00888                 if (!n--) {
00889                         return 0;               // strings are equal until end point
00890                 }
00891                 
00892                 if (c1 != c2) {
00893                         return c1 < c2 ? -1 : 1;
00894                 }
00895         } while (c1);
00896         
00897         return 0;               // strings are equal
00898 }
00899 
00900 int Q_stricmp (const char *s1, const char *s2) {
00901         return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
00902 }
00903 
00904 
00905 char *Q_strlwr( char *s1 ) {
00906     char        *s;
00907 
00908     s = s1;
00909         while ( *s ) {
00910                 *s = tolower(*s);
00911                 s++;
00912         }
00913     return s1;
00914 }
00915 
00916 char *Q_strupr( char *s1 ) {
00917     char        *s;
00918 
00919     s = s1;
00920         while ( *s ) {
00921                 *s = toupper(*s);
00922                 s++;
00923         }
00924     return s1;
00925 }
00926 
00927 
00928 // never goes past bounds or leaves without a terminating 0
00929 void Q_strcat( char *dest, int size, const char *src ) {
00930         int             l1;
00931 
00932         l1 = strlen( dest );
00933         if ( l1 >= size ) {
00934                 Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
00935         }
00936         Q_strncpyz( dest + l1, src, size - l1 );
00937 }
00938 
00939 
00940 int Q_PrintStrlen( const char *string ) {
00941         int                     len;
00942         const char      *p;
00943 
00944         if( !string ) {
00945                 return 0;
00946         }
00947 
00948         len = 0;
00949         p = string;
00950         while( *p ) {
00951                 if( Q_IsColorString( p ) ) {
00952                         p += 2;
00953                         continue;
00954                 }
00955                 p++;
00956                 len++;
00957         }
00958 
00959         return len;
00960 }
00961 
00962 
00963 char *Q_CleanStr( char *string ) {
00964         char*   d;
00965         char*   s;
00966         int             c;
00967 
00968         s = string;
00969         d = string;
00970         while ((c = *s) != 0 ) {
00971                 if ( Q_IsColorString( s ) ) {
00972                         s++;
00973                 }               
00974                 else if ( c >= 0x20 && c <= 0x7E ) {
00975                         *d++ = c;
00976                 }
00977                 s++;
00978         }
00979         *d = '\0';
00980 
00981         return string;
00982 }
00983 
00984 
00985 void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
00986         int             len;
00987         va_list         argptr;
00988         char    bigbuffer[32000];       // big, but small enough to fit in PPC stack
00989 
00990         va_start (argptr,fmt);
00991         len = vsprintf (bigbuffer,fmt,argptr);
00992         va_end (argptr);
00993         if ( len >= sizeof( bigbuffer ) ) {
00994                 Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
00995         }
00996         if (len >= size) {
00997                 Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
00998 #ifdef  _DEBUG
00999                 __asm {
01000                         int 3;
01001                 }
01002 #endif
01003         }
01004         Q_strncpyz (dest, bigbuffer, size );
01005 }
01006 
01007 
01008 /*
01009 ============
01010 va
01011 
01012 does a varargs printf into a temp buffer, so I don't need to have
01013 varargs versions of all text functions.
01014 FIXME: make this buffer size safe someday
01015 ============
01016 */
01017 char    * QDECL va( const char *format, ... ) {
01018         va_list         argptr;
01019         static char             string[2][32000];       // in case va is called by nested functions
01020         static int              index = 0;
01021         char    *buf;
01022 
01023         buf = string[index & 1];
01024         index++;
01025 
01026         va_start (argptr, format);
01027         vsprintf (buf, format,argptr);
01028         va_end (argptr);
01029 
01030         return buf;
01031 }
01032 
01033 
01034 /*
01035 =====================================================================
01036 
01037   INFO STRINGS
01038 
01039 =====================================================================
01040 */
01041 
01042 /*
01043 ===============
01044 Info_ValueForKey
01045 
01046 Searches the string for the given
01047 key and returns the associated value, or an empty string.
01048 FIXME: overflow check?
01049 ===============
01050 */
01051 char *Info_ValueForKey( const char *s, const char *key ) {
01052         char    pkey[BIG_INFO_KEY];
01053         static  char value[2][BIG_INFO_VALUE];  // use two buffers so compares
01054                                                                                         // work without stomping on each other
01055         static  int     valueindex = 0;
01056         char    *o;
01057         
01058         if ( !s || !key ) {
01059                 return "";
01060         }
01061 
01062         if ( strlen( s ) >= BIG_INFO_STRING ) {
01063                 Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
01064         }
01065 
01066         valueindex ^= 1;
01067         if (*s == '\\')
01068                 s++;
01069         while (1)
01070         {
01071                 o = pkey;
01072                 while (*s != '\\')
01073                 {
01074                         if (!*s)
01075                                 return "";
01076                         *o++ = *s++;
01077                 }
01078                 *o = 0;
01079                 s++;
01080 
01081                 o = value[valueindex];
01082 
01083                 while (*s != '\\' && *s)
01084                 {
01085                         *o++ = *s++;
01086                 }
01087                 *o = 0;
01088 
01089                 if (!Q_stricmp (key, pkey) )
01090                         return value[valueindex];
01091 
01092                 if (!*s)
01093                         break;
01094                 s++;
01095         }
01096 
01097         return "";
01098 }
01099 
01100 
01101 /*
01102 ===================
01103 Info_NextPair
01104 
01105 Used to itterate through all the key/value pairs in an info string
01106 ===================
01107 */
01108 void Info_NextPair( const char **head, char *key, char *value ) {
01109         char    *o;
01110         const char      *s;
01111 
01112         s = *head;
01113 
01114         if ( *s == '\\' ) {
01115                 s++;
01116         }
01117         key[0] = 0;
01118         value[0] = 0;
01119 
01120         o = key;
01121         while ( *s != '\\' ) {
01122                 if ( !*s ) {
01123                         *o = 0;
01124                         *head = s;
01125                         return;
01126                 }
01127                 *o++ = *s++;
01128         }
01129         *o = 0;
01130         s++;
01131 
01132         o = value;
01133         while ( *s != '\\' && *s ) {
01134                 *o++ = *s++;
01135         }
01136         *o = 0;
01137 
01138         *head = s;
01139 }
01140 
01141 
01142 /*
01143 ===================
01144 Info_RemoveKey
01145 ===================
01146 */
01147 void Info_RemoveKey( char *s, const char *key ) {
01148         char    *start;
01149         char    pkey[MAX_INFO_KEY];
01150         char    value[MAX_INFO_VALUE];
01151         char    *o;
01152 
01153         if ( strlen( s ) >= MAX_INFO_STRING ) {
01154                 Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
01155         }
01156 
01157         if (strchr (key, '\\')) {
01158                 return;
01159         }
01160 
01161         while (1)
01162         {
01163                 start = s;
01164                 if (*s == '\\')
01165                         s++;
01166                 o = pkey;
01167                 while (*s != '\\')
01168                 {
01169                         if (!*s)
01170                                 return;
01171                         *o++ = *s++;
01172                 }
01173                 *o = 0;
01174                 s++;
01175 
01176                 o = value;
01177                 while (*s != '\\' && *s)
01178                 {
01179                         if (!*s)
01180                                 return;
01181                         *o++ = *s++;
01182                 }
01183                 *o = 0;
01184 
01185                 if (!strcmp (key, pkey) )
01186                 {
01187                         strcpy (start, s);      // remove this part
01188                         return;
01189                 }
01190 
01191                 if (!*s)
01192                         return;
01193         }
01194 
01195 }
01196 
01197 /*
01198 ===================
01199 Info_RemoveKey_Big
01200 ===================
01201 */
01202 void Info_RemoveKey_Big( char *s, const char *key ) {
01203         char    *start;
01204         char    pkey[BIG_INFO_KEY];
01205         char    value[BIG_INFO_VALUE];
01206         char    *o;
01207 
01208         if ( strlen( s ) >= BIG_INFO_STRING ) {
01209                 Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
01210         }
01211 
01212         if (strchr (key, '\\')) {
01213                 return;
01214         }
01215 
01216         while (1)
01217         {
01218                 start = s;
01219                 if (*s == '\\')
01220                         s++;
01221                 o = pkey;
01222                 while (*s != '\\')
01223                 {
01224                         if (!*s)
01225                                 return;
01226                         *o++ = *s++;
01227                 }
01228                 *o = 0;
01229                 s++;
01230 
01231                 o = value;
01232                 while (*s != '\\' && *s)
01233                 {
01234                         if (!*s)
01235                                 return;
01236                         *o++ = *s++;
01237                 }
01238                 *o = 0;
01239 
01240                 if (!strcmp (key, pkey) )
01241                 {
01242                         strcpy (start, s);      // remove this part
01243                         return;
01244                 }
01245 
01246                 if (!*s)
01247                         return;
01248         }
01249 
01250 }
01251 
01252 
01253 
01254 
01255 /*
01256 ==================
01257 Info_Validate
01258 
01259 Some characters are illegal in info strings because they
01260 can mess up the server's parsing
01261 ==================
01262 */
01263 qboolean Info_Validate( const char *s ) {
01264         if ( strchr( s, '\"' ) ) {
01265                 return qfalse;
01266         }
01267         if ( strchr( s, ';' ) ) {
01268                 return qfalse;
01269         }
01270         return qtrue;
01271 }
01272 
01273 /*
01274 ==================
01275 Info_SetValueForKey
01276 
01277 Changes or adds a key/value pair
01278 ==================
01279 */
01280 void Info_SetValueForKey( char *s, const char *key, const char *value ) {
01281         char    newi[MAX_INFO_STRING];
01282 
01283         if ( strlen( s ) >= MAX_INFO_STRING ) {
01284                 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
01285         }
01286 
01287         if (strchr (key, '\\') || strchr (value, '\\'))
01288         {
01289                 Com_Printf ("Can't use keys or values with a \\\n");
01290                 return;
01291         }
01292 
01293         if (strchr (key, ';') || strchr (value, ';'))
01294         {
01295                 Com_Printf ("Can't use keys or values with a semicolon\n");
01296                 return;
01297         }
01298 
01299         if (strchr (key, '\"') || strchr (value, '\"'))
01300         {
01301                 Com_Printf ("Can't use keys or values with a \"\n");
01302                 return;
01303         }
01304 
01305         Info_RemoveKey (s, key);
01306         if (!value || !strlen(value))
01307                 return;
01308 
01309         Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
01310 
01311         if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
01312         {
01313                 Com_Printf ("Info string length exceeded\n");
01314                 return;
01315         }
01316 
01317         strcat (newi, s);
01318         strcpy (s, newi);
01319 }
01320 
01321 /*
01322 ==================
01323 Info_SetValueForKey_Big
01324 
01325 Changes or adds a key/value pair
01326 ==================
01327 */
01328 void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
01329         char    newi[BIG_INFO_STRING];
01330 
01331         if ( strlen( s ) >= BIG_INFO_STRING ) {
01332                 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
01333         }
01334 
01335         if (strchr (key, '\\') || strchr (value, '\\'))
01336         {
01337                 Com_Printf ("Can't use keys or values with a \\\n");
01338                 return;
01339         }
01340 
01341         if (strchr (key, ';') || strchr (value, ';'))
01342         {
01343                 Com_Printf ("Can't use keys or values with a semicolon\n");
01344                 return;
01345         }
01346 
01347         if (strchr (key, '\"') || strchr (value, '\"'))
01348         {
01349                 Com_Printf ("Can't use keys or values with a \"\n");
01350                 return;
01351         }
01352 
01353         Info_RemoveKey_Big (s, key);
01354         if (!value || !strlen(value))
01355                 return;
01356 
01357         Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
01358 
01359         if (strlen(newi) + strlen(s) > BIG_INFO_STRING)
01360         {
01361                 Com_Printf ("BIG Info string length exceeded\n");
01362                 return;
01363         }
01364 
01365         strcat (s, newi);
01366 }
01367 
01368 //====================================================================
01369 
01370