Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

q_shared.c

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

Generated on Thu Aug 25 12:37:34 2005 for Quake III Arena by  doxygen 1.3.9.1