00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "q_shared.hpp"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 extern "C" void *Com_Allocate( int bytes );
00035 extern "C" void Com_Dealloc( void *ptr );
00036
00037 void Com_InitGrowList( growList_t *list, int maxElements ) {
00038 list->maxElements = maxElements;
00039 list->currentElements = 0;
00040 list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
00041 }
00042
00043 int Com_AddToGrowList( growList_t *list, void *data ) {
00044 void **old;
00045
00046 if ( list->currentElements != list->maxElements ) {
00047 list->elements[list->currentElements] = data;
00048 return list->currentElements++;
00049 }
00050
00051
00052 old = list->elements;
00053
00054 if ( list->maxElements < 0 ) {
00055 Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
00056 }
00057
00058 if ( list->maxElements == 0 ) {
00059
00060 Com_InitGrowList( list, 100 );
00061 return Com_AddToGrowList( list, data );
00062 }
00063
00064 list->maxElements *= 2;
00065
00066 Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
00067
00068 list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
00069
00070 if ( !list->elements ) {
00071 Com_Error( ERR_DROP, "Growlist alloc failed" );
00072 }
00073
00074 memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
00075
00076 Com_Dealloc( old );
00077
00078 return Com_AddToGrowList( list, data );
00079 }
00080
00081 void *Com_GrowListElement( const growList_t *list, int index ) {
00082 if ( index < 0 || index >= list->currentElements ) {
00083 Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
00084 index, list->currentElements );
00085 }
00086 return list->elements[index];
00087 }
00088
00089 int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
00090 int i;
00091
00092 for ( i = 0 ; i < list->currentElements ; i++ ) {
00093 if ( list->elements[i] == element ) {
00094 return i;
00095 }
00096 }
00097 return -1;
00098 }
00099
00100
00101
00102
00103 float Com_Clamp( float min, float max, float value ) {
00104 if ( value < min ) {
00105 return min;
00106 }
00107 if ( value > max ) {
00108 return max;
00109 }
00110 return value;
00111 }
00112
00113
00114
00115
00116
00117
00118 const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
00119 int len, i, j;
00120
00121 len = strlen(str1) - strlen(str2);
00122 for (i = 0; i <= len; i++, str1++) {
00123 for (j = 0; str2[j]; j++) {
00124 if (casesensitive) {
00125 if (str1[j] != str2[j]) {
00126 break;
00127 }
00128 }
00129 else {
00130 if (toupper(str1[j]) != toupper(str2[j])) {
00131 break;
00132 }
00133 }
00134 }
00135 if (!str2[j]) {
00136 return str1;
00137 }
00138 }
00139 return NULL;
00140 }
00141
00142
00143
00144
00145
00146
00147 int Com_Filter( const char *filter, const char *name, int casesensitive)
00148 {
00149 char buf[MAX_TOKEN_CHARS];
00150 const char *ptr;
00151 int i, found;
00152
00153 while(*filter) {
00154 if (*filter == '*') {
00155 filter++;
00156 for (i = 0; *filter; i++) {
00157 if (*filter == '*' || *filter == '?') break;
00158 buf[i] = *filter;
00159 filter++;
00160 }
00161 buf[i] = '\0';
00162 if (strlen(buf)) {
00163 ptr = Com_StringContains(name, buf, casesensitive);
00164 if (!ptr) return qfalse;
00165 name = ptr + strlen(buf);
00166 }
00167 }
00168 else if (*filter == '?') {
00169 filter++;
00170 name++;
00171 }
00172 else if (*filter == '[' && *(filter+1) == '[') {
00173 filter++;
00174 }
00175 else if (*filter == '[') {
00176 filter++;
00177 found = qfalse;
00178 while(*filter && !found) {
00179 if (*filter == ']' && *(filter+1) != ']') break;
00180 if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
00181 if (casesensitive) {
00182 if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
00183 }
00184 else {
00185 if (toupper(*name) >= toupper(*filter) &&
00186 toupper(*name) <= toupper(*(filter+2))) found = qtrue;
00187 }
00188 filter += 3;
00189 }
00190 else {
00191 if (casesensitive) {
00192 if (*filter == *name) found = qtrue;
00193 }
00194 else {
00195 if (toupper(*filter) == toupper(*name)) found = qtrue;
00196 }
00197 filter++;
00198 }
00199 }
00200 if (!found) return qfalse;
00201 while(*filter) {
00202 if (*filter == ']' && *(filter+1) != ']') break;
00203 filter++;
00204 }
00205 filter++;
00206 name++;
00207 }
00208 else {
00209 if (casesensitive) {
00210 if (*filter != *name) return qfalse;
00211 }
00212 else {
00213 if (toupper(*filter) != toupper(*name)) return qfalse;
00214 }
00215 filter++;
00216 name++;
00217 }
00218 }
00219 return qtrue;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229 int Com_HashString( const char *fname ) {
00230 int i;
00231 long hash;
00232 char letter;
00233
00234 hash = 0;
00235 i = 0;
00236 while (fname[i] != '\0') {
00237 letter = tolower(fname[i]);
00238 if (letter =='.') break;
00239 if (letter =='\\') letter = '/';
00240 hash+=(long)(letter)*(i+119);
00241 i++;
00242 }
00243 hash &= (FILE_HASH_SIZE-1);
00244 return hash;
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 char *Com_SkipPath (char *pathname)
00254 {
00255 char *last;
00256
00257 last = pathname;
00258 while (*pathname)
00259 {
00260 if (*pathname=='/')
00261 last = pathname+1;
00262 pathname++;
00263 }
00264 return last;
00265 }
00266
00267
00268
00269
00270
00271
00272 void Com_StripExtension( const char *in, char *out ) {
00273 while ( *in && *in != '.' ) {
00274 *out++ = *in++;
00275 }
00276 *out = 0;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 void Com_DefaultExtension (char *path, int maxSize, const char *extension ) {
00286 char oldPath[MAX_QPATH];
00287 char *src;
00288
00289
00290
00291
00292
00293 src = path + strlen(path) - 1;
00294
00295 while (*src != '/' && src != path) {
00296 if ( *src == '.' ) {
00297 return;
00298 }
00299 src--;
00300 }
00301
00302 Q_strncpyz( oldPath, path, sizeof( oldPath ) );
00303 Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 static short (*_BigShort) (short l);
00317 static short (*_LittleShort) (short l);
00318 static int (*_BigLong) (int l);
00319 static int (*_LittleLong) (int l);
00320 static float (*_BigFloat) (float l);
00321 static float (*_LittleFloat) (float l);
00322
00323 short BigShort(short l){return _BigShort(l);}
00324 short LittleShort(short l) {return _LittleShort(l);}
00325 int BigLong (int l) {return _BigLong(l);}
00326 int LittleLong (int l) {return _LittleLong(l);}
00327 float BigFloat (float l) {return _BigFloat(l);}
00328 float LittleFloat (float l) {return _LittleFloat(l);}
00329
00330 short ShortSwap (short l)
00331 {
00332 byte b1,b2;
00333
00334 b1 = l&255;
00335 b2 = (l>>8)&255;
00336
00337 return (b1<<8) + b2;
00338 }
00339
00340 short ShortNoSwap (short l)
00341 {
00342 return l;
00343 }
00344
00345 int LongSwap (int l)
00346 {
00347 byte b1,b2,b3,b4;
00348
00349 b1 = l&255;
00350 b2 = (l>>8)&255;
00351 b3 = (l>>16)&255;
00352 b4 = (l>>24)&255;
00353
00354 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
00355 }
00356
00357 int LongNoSwap (int l)
00358 {
00359 return l;
00360 }
00361
00362 float FloatSwap (float f)
00363 {
00364 union
00365 {
00366 float f;
00367 byte b[4];
00368 } dat1, dat2;
00369
00370
00371 dat1.f = f;
00372 dat2.b[0] = dat1.b[3];
00373 dat2.b[1] = dat1.b[2];
00374 dat2.b[2] = dat1.b[1];
00375 dat2.b[3] = dat1.b[0];
00376 return dat2.f;
00377 }
00378
00379 float FloatNoSwap (float f)
00380 {
00381 return f;
00382 }
00383
00384
00385
00386
00387
00388
00389 void Swap_Init (void)
00390 {
00391 byte swaptest[2] = {1,0};
00392
00393
00394 if ( *(short *)swaptest == 1)
00395 {
00396 _BigShort = ShortSwap;
00397 _LittleShort = ShortNoSwap;
00398 _BigLong = LongSwap;
00399 _LittleLong = LongNoSwap;
00400 _BigFloat = FloatSwap;
00401 _LittleFloat = FloatNoSwap;
00402 }
00403 else
00404 {
00405 _BigShort = ShortNoSwap;
00406 _LittleShort = ShortSwap;
00407 _BigLong = LongNoSwap;
00408 _LittleLong = LongSwap;
00409 _BigFloat = FloatNoSwap;
00410 _LittleFloat = FloatSwap;
00411 }
00412
00413 }
00414
00415
00416
00417
00418
00419
00420 int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
00421 const char *token;
00422 int count;
00423 char key[MAX_TOKEN_CHARS];
00424
00425 count = 0;
00426
00427 while ( 1 ) {
00428 token = Com_Parse( &buf );
00429 if ( !token[0] ) {
00430 break;
00431 }
00432 if ( strcmp( token, "{" ) ) {
00433 Com_Printf( "Missing { in info file\n" );
00434 break;
00435 }
00436
00437 if ( count == max ) {
00438 Com_Printf( "Max infos exceeded\n" );
00439 break;
00440 }
00441
00442 infos[count][0] = 0;
00443 while ( 1 ) {
00444 token = Com_Parse( &buf );
00445 if ( !token[0] ) {
00446 Com_Printf( "Unexpected end of info file\n" );
00447 break;
00448 }
00449 if ( !strcmp( token, "}" ) ) {
00450 break;
00451 }
00452 Q_strncpyz( key, token, sizeof( key ) );
00453
00454 token = Com_ParseOnLine( &buf );
00455 if ( !token[0] ) {
00456 token = "<NULL>";
00457 }
00458 Info_SetValueForKey( infos[count], key, token );
00459 }
00460 count++;
00461 }
00462
00463 return count;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 int Q_isprint( int c )
00477 {
00478 if ( c >= 0x20 && c <= 0x7E )
00479 return ( 1 );
00480 return ( 0 );
00481 }
00482
00483 int Q_islower( int c )
00484 {
00485 if (c >= 'a' && c <= 'z')
00486 return ( 1 );
00487 return ( 0 );
00488 }
00489
00490 int Q_isupper( int c )
00491 {
00492 if (c >= 'A' && c <= 'Z')
00493 return ( 1 );
00494 return ( 0 );
00495 }
00496
00497 int Q_isalpha( int c )
00498 {
00499 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
00500 return ( 1 );
00501 return ( 0 );
00502 }
00503
00504 char* Q_strrchr( const char* string, int c )
00505 {
00506 char cc = c;
00507 char *s;
00508 char *sp=(char *)0;
00509
00510 s = (char*)string;
00511
00512 while (*s)
00513 {
00514 if (*s == cc)
00515 sp = s;
00516 s++;
00517 }
00518 if (cc == 0)
00519 sp = s;
00520
00521 return sp;
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531 void Q_strncpyz( char *dest, const char *src, int destsize ) {
00532 if ( !src ) {
00533 Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
00534 }
00535 if ( destsize < 1 ) {
00536 Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
00537 }
00538
00539 strncpy( dest, src, destsize-1 );
00540 dest[destsize-1] = 0;
00541 }
00542
00543 int Q_stricmpn (const char *s1, const char *s2, int n) {
00544 int c1, c2;
00545
00546 do {
00547 c1 = *s1++;
00548 c2 = *s2++;
00549
00550 if (!n--) {
00551 return 0;
00552 }
00553
00554 if (c1 != c2) {
00555 if (c1 >= 'a' && c1 <= 'z') {
00556 c1 -= ('a' - 'A');
00557 }
00558 if (c2 >= 'a' && c2 <= 'z') {
00559 c2 -= ('a' - 'A');
00560 }
00561 if (c1 != c2) {
00562 return c1 < c2 ? -1 : 1;
00563 }
00564 }
00565 } while (c1);
00566
00567 return 0;
00568 }
00569
00570 int Q_strncmp (const char *s1, const char *s2, int n) {
00571 int c1, c2;
00572
00573 do {
00574 c1 = *s1++;
00575 c2 = *s2++;
00576
00577 if (!n--) {
00578 return 0;
00579 }
00580
00581 if (c1 != c2) {
00582 return c1 < c2 ? -1 : 1;
00583 }
00584 } while (c1);
00585
00586 return 0;
00587 }
00588
00589 int Q_stricmp (const char *s1, const char *s2) {
00590 return Q_stricmpn (s1, s2, 99999);
00591 }
00592
00593
00594 char *Q_strlwr( char *s1 ) {
00595 char *s;
00596
00597 s = s1;
00598 while ( *s ) {
00599 *s = tolower(*s);
00600 s++;
00601 }
00602 return s1;
00603 }
00604
00605 char *Q_strupr( char *s1 ) {
00606 char *s;
00607
00608 s = s1;
00609 while ( *s ) {
00610 *s = toupper(*s);
00611 s++;
00612 }
00613 return s1;
00614 }
00615
00616
00617
00618 void Q_strcat( char *dest, int size, const char *src ) {
00619 int l1;
00620
00621 l1 = strlen( dest );
00622 if ( l1 >= size ) {
00623 Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
00624 }
00625 Q_strncpyz( dest + l1, src, size - l1 );
00626 }
00627
00628
00629 int Q_PrintStrlen( const char *string ) {
00630 int len;
00631 const char *p;
00632
00633 if( !string ) {
00634 return 0;
00635 }
00636
00637 len = 0;
00638 p = string;
00639 while( *p ) {
00640 if( Q_IsColorString( p ) ) {
00641 p += 2;
00642 continue;
00643 }
00644 p++;
00645 len++;
00646 }
00647
00648 return len;
00649 }
00650
00651
00652 char *Q_CleanStr( char *string ) {
00653 char* d;
00654 char* s;
00655 int c;
00656
00657 s = string;
00658 d = string;
00659 while ((c = *s) != 0 ) {
00660 if ( Q_IsColorString( s ) ) {
00661 s++;
00662 }
00663 else if ( c >= 0x20 && c <= 0x7E ) {
00664 *d++ = c;
00665 }
00666 s++;
00667 }
00668 *d = '\0';
00669
00670 return string;
00671 }
00672
00673
00674 void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
00675 int len;
00676 va_list argptr;
00677 char bigbuffer[32000];
00678
00679 va_start (argptr,fmt);
00680 len = vsprintf (bigbuffer,fmt,argptr);
00681 va_end (argptr);
00682 if ( len >= sizeof( bigbuffer ) ) {
00683 Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
00684 }
00685 if (len >= size) {
00686 Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
00687 }
00688 Q_strncpyz (dest, bigbuffer, size );
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701 char * QDECL va( char *format, ... ) {
00702 va_list argptr;
00703 static char string[2][32000];
00704 static int index = 0;
00705 char *buf;
00706
00707 buf = string[index & 1];
00708 index++;
00709
00710 va_start (argptr, format);
00711 vsprintf (buf, format,argptr);
00712 va_end (argptr);
00713
00714 return buf;
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 char *Info_ValueForKey( const char *s, const char *key ) {
00736 char pkey[MAX_INFO_KEY];
00737 static char value[2][MAX_INFO_VALUE];
00738
00739 static int valueindex = 0;
00740 char *o;
00741
00742 if ( !s || !key ) {
00743 return "";
00744 }
00745
00746 if ( strlen( s ) >= MAX_INFO_STRING ) {
00747 Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
00748 }
00749
00750 valueindex ^= 1;
00751 if (*s == '\\')
00752 s++;
00753 while (1)
00754 {
00755 o = pkey;
00756 while (*s != '\\')
00757 {
00758 if (!*s)
00759 return "";
00760 *o++ = *s++;
00761 }
00762 *o = 0;
00763 s++;
00764
00765 o = value[valueindex];
00766
00767 while (*s != '\\' && *s)
00768 {
00769 *o++ = *s++;
00770 }
00771 *o = 0;
00772
00773 if (!Q_stricmp (key, pkey) )
00774 return value[valueindex];
00775
00776 if (!*s)
00777 break;
00778 s++;
00779 }
00780
00781 return "";
00782 }
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
00793 char *o;
00794 const char *s;
00795
00796 s = *head;
00797
00798 if ( *s == '\\' ) {
00799 s++;
00800 }
00801 key[0] = 0;
00802 value[0] = 0;
00803
00804 o = key;
00805 while ( *s != '\\' ) {
00806 if ( !*s ) {
00807 *o = 0;
00808 *head = s;
00809 return;
00810 }
00811 *o++ = *s++;
00812 }
00813 *o = 0;
00814 s++;
00815
00816 o = value;
00817 while ( *s != '\\' && *s ) {
00818 *o++ = *s++;
00819 }
00820 *o = 0;
00821
00822 *head = s;
00823 }
00824
00825
00826
00827
00828
00829
00830
00831 void Info_RemoveKey( char *s, const char *key ) {
00832 char *start;
00833 char pkey[MAX_INFO_KEY];
00834 char value[MAX_INFO_VALUE];
00835 char *o;
00836
00837 if ( strlen( s ) >= MAX_INFO_STRING ) {
00838 Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
00839 }
00840
00841 if (strchr (key, '\\')) {
00842 return;
00843 }
00844
00845 while (1)
00846 {
00847 start = s;
00848 if (*s == '\\')
00849 s++;
00850 o = pkey;
00851 while (*s != '\\')
00852 {
00853 if (!*s)
00854 return;
00855 *o++ = *s++;
00856 }
00857 *o = 0;
00858 s++;
00859
00860 o = value;
00861 while (*s != '\\' && *s)
00862 {
00863 if (!*s)
00864 return;
00865 *o++ = *s++;
00866 }
00867 *o = 0;
00868
00869 if (!strcmp (key, pkey) )
00870 {
00871 strcpy (start, s);
00872 return;
00873 }
00874
00875 if (!*s)
00876 return;
00877 }
00878
00879 }
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 qboolean Info_Validate( const char *s ) {
00891 if ( strchr( s, '\"' ) ) {
00892 return qfalse;
00893 }
00894 if ( strchr( s, ';' ) ) {
00895 return qfalse;
00896 }
00897 return qtrue;
00898 }
00899
00900
00901
00902
00903
00904
00905
00906
00907 void Info_SetValueForKey( char *s, const char *key, const char *value ) {
00908 char newi[MAX_INFO_STRING];
00909
00910 if ( strlen( s ) >= MAX_INFO_STRING ) {
00911 Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
00912 }
00913
00914 if (strchr (key, '\\') || strchr (value, '\\'))
00915 {
00916 Com_Printf ("Can't use keys or values with a \\\n");
00917 return;
00918 }
00919
00920 if (strchr (key, ';') || strchr (value, ';'))
00921 {
00922 Com_Printf ("Can't use keys or values with a semicolon\n");
00923 return;
00924 }
00925
00926 if (strchr (key, '\"') || strchr (value, '\"'))
00927 {
00928 Com_Printf ("Can't use keys or values with a \"\n");
00929 return;
00930 }
00931
00932 Info_RemoveKey (s, key);
00933 if (!value || !strlen(value))
00934 return;
00935
00936 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
00937
00938 if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
00939 {
00940 Com_Printf ("Info string length exceeded\n");
00941 return;
00942 }
00943
00944 strcat (s, newi);
00945 }
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955 int ParseHex( const char *text ) {
00956 int value;
00957 int c;
00958
00959 value = 0;
00960 while ( ( c = *text++ ) != 0 ) {
00961 if ( c >= '0' && c <= '9' ) {
00962 value = value * 16 + c - '0';
00963 continue;
00964 }
00965 if ( c >= 'a' && c <= 'f' ) {
00966 value = value * 16 + 10 + c - 'a';
00967 continue;
00968 }
00969 if ( c >= 'A' && c <= 'F' ) {
00970 value = value * 16 + 10 + c - 'A';
00971 continue;
00972 }
00973 }
00974
00975 return value;
00976 }