qboolean Q_stricmpext( const char *pattern, const char *text ) { char c; while(( c = *pattern++ ) != '\0' ) { switch( c ) { case '?': if( *text++ == '\0' ) return false; break; case '\\': if( Q_tolower( *pattern++ ) != Q_tolower( *text++ )) return false; break; case '*': return Q_starcmp( pattern, text ); default: if( Q_tolower( c ) != Q_tolower( *text++ )) return false; } } return true; }
/* ===================================== Cmd_GetCdCommands Prints or complete CD command name ===================================== */ qboolean Cmd_GetCdCommands( const char *s, char *completedname, int length ) { int i, numcdcommands; string cdcommands[8]; string matchbuf; const char *cd_command[] = { "info", "loop", "off", "on", "pause", "play", "resume", "stop", }; // compare CD command list with current keyword for( i = 0, numcdcommands = 0; i < 8; i++ ) { if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, Q_strlen( s ))) Q_strcpy( cdcommands[numcdcommands++], cd_command[i] ); } if( !numcdcommands ) return false; Q_strncpy( matchbuf, cdcommands[0], MAX_STRING ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( numcdcommands == 1 ) return true; for( i = 0; i < numcdcommands; i++ ) { Q_strncpy( matchbuf, cdcommands[i], MAX_STRING ); Msg( "%16s\n", matchbuf ); } Msg( "\n^3 %i commands found.\n", numcdcommands ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ===================================== Cmd_GetTexturemodes Prints or complete sound filename ===================================== */ qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length ) { int i, numtexturemodes; string texturemodes[6]; // keep an actual ( sizeof( gl_texturemode) / sizeof( gl_texturemode[0] )) string matchbuf; const char *gl_texturemode[] = { "GL_LINEAR", "GL_LINEAR_MIPMAP_LINEAR", "GL_LINEAR_MIPMAP_NEAREST", "GL_NEAREST", "GL_NEAREST_MIPMAP_LINEAR", "GL_NEAREST_MIPMAP_NEAREST", }; // compare gamelist with current keyword for( i = 0, numtexturemodes = 0; i < 6; i++ ) { if(( *s == '*' ) || !Q_strnicmp( gl_texturemode[i], s, Q_strlen( s ))) Q_strcpy( texturemodes[numtexturemodes++], gl_texturemode[i] ); } if( !numtexturemodes ) return false; Q_strncpy( matchbuf, gl_texturemode[0], MAX_STRING ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( numtexturemodes == 1 ) return true; for( i = 0; i < numtexturemodes; i++ ) { Q_strncpy( matchbuf, texturemodes[i], MAX_STRING ); Msg( "%16s\n", matchbuf ); } Msg( "\n^3 %i filters found.\n", numtexturemodes ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ================= COM_HashKey returns hash key for string ================= */ unsigned int COM_HashKey( const char *string, unsigned int hashSize ) { unsigned int hashKey = 0; for( int i = 0; string[i]; i++ ) hashKey = (hashKey + i) * 37 + Q_tolower( string[i] ); return (hashKey % hashSize); }
int Q_strcasecmp( const char *s1, const char *s2 ) { int c1, c2; do { c1 = *s1++; c2 = *s2++; if( c1 != c2 ) { c1 = Q_tolower( c1 ); c2 = Q_tolower( c2 ); if( c1 < c2 ) return -1; if( c1 > c2 ) return 1; /* strings not equal */ } } while( c1 ); return 0; /* strings are equal */ }
/* ===================================== Cmd_GetSoundList Prints or complete sound filename ===================================== */ qboolean Cmd_GetSoundList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numsounds; const char *snddir = "sound/"; // constant t = FS_Search( va( "%s%s*.*", snddir, s ), true, false ); if( !t ) return false; Q_strncpy( matchbuf, t->filenames[0] + Q_strlen( snddir ), MAX_STRING ); FS_StripExtension( matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for(i = 0, numsounds = 0; i < t->numfilenames; i++) { const char *ext = FS_FileExtension( t->filenames[i] ); if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" )); else continue; Q_strncpy( matchbuf, t->filenames[i] + Q_strlen(snddir), MAX_STRING ); FS_StripExtension( matchbuf ); Msg( "%16s\n", matchbuf ); numsounds++; } Msg( "\n^3 %i sounds found.\n", numsounds ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
uint32 Com_HashGeneric (const String &name, const sint32 hashSize) { uint32 hashValue = 0; for (uint32 i = 0; name[i]; i++) { sint32 ch = Q_tolower(name[i]); hashValue = hashValue * 33 + ch; } return (hashValue + (hashValue >> 5)) & (hashSize-1); }
/* ================ Com_HashGeneric hashSize MUST be a power of two! From EGL, used to make table lookups a bit faster. ================ */ uint32 Com_HashGeneric (const char *name, const sint32 hashSize) { uint32 hashValue = 0; for ( ; *name; ) { sint32 ch = Q_tolower(*(name++)); hashValue = hashValue * 33 + ch; } return (hashValue + (hashValue >> 5)) & (hashSize-1); }
/* ===================================== Cmd_GetGameList Prints or complete gamedir name ===================================== */ qboolean Cmd_GetGamesList( const char *s, char *completedname, int length ) { int i, numgamedirs; string gamedirs[MAX_MODS]; string matchbuf; // stand-alone games doesn't have cmd "game" if( !Cmd_Exists( "game" )) return false; // compare gamelist with current keyword for( i = 0, numgamedirs = 0; i < SI.numgames; i++ ) { if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, Q_strlen( s ))) Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder ); } if( !numgamedirs ) return false; Q_strncpy( matchbuf, gamedirs[0], MAX_STRING ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( numgamedirs == 1 ) return true; for( i = 0; i < numgamedirs; i++ ) { Q_strncpy( matchbuf, gamedirs[i], MAX_STRING ); Msg( "%16s\n", matchbuf ); } Msg( "\n^3 %i games found.\n", numgamedirs ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ===================================== Cmd_GetMusicList Prints or complete background track filename ===================================== */ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numtracks; t = FS_Search( va( "media/%s*.*", s ), true, false ); if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for(i = 0, numtracks = 0; i < t->numfilenames; i++) { const char *ext = FS_FileExtension( t->filenames[i] ); if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" )); else continue; FS_FileBase( t->filenames[i], matchbuf ); Msg( "%16s\n", matchbuf ); numtracks++; } Msg( "\n^3 %i soundtracks found.\n", numtracks ); Mem_Free(t); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
int Q_strncasecmp( const char *s1, const char *s2, size_t n ) { int c1, c2; do { c1 = *s1++; c2 = *s2++; if( !n-- ) return 0; /* strings are equal until end point */ if( c1 != c2 ) { c1 = Q_tolower( c1 ); c2 = Q_tolower( c2 ); if( c1 < c2 ) return -1; if( c1 > c2 ) return 1; /* strings not equal */ } } while( c1 ); return 0; /* strings are equal */ }
/* ===================================== Cmd_GetConfigList Prints or complete .cfg filename ===================================== */ qboolean Cmd_GetConfigList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numconfigs; t = FS_Search( va( "%s*.cfg", s ), true, false ); if( !t ) return false; Q_strncpy( matchbuf, t->filenames[0], 256 ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, numconfigs = 0; i < t->numfilenames; i++ ) { const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "cfg" )) continue; Q_strncpy( matchbuf, t->filenames[i], 256 ); Msg( "%16s\n", matchbuf ); numconfigs++; } Msg( "\n^3 %i configs found.\n", numconfigs ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ===================================== Cmd_GetItemsList Prints or complete item classname (weapons only) ===================================== */ qboolean Cmd_GetItemsList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numitems; if( !clgame.itemspath[0] ) return false; // not in game yet t = FS_Search( va( "%s/%s*.txt", clgame.itemspath, s ), true, false ); if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for(i = 0, numitems = 0; i < t->numfilenames; i++) { const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "txt" )) continue; FS_FileBase( t->filenames[i], matchbuf ); Msg( "%16s\n", matchbuf ); numitems++; } Msg( "\n^3 %i items found.\n", numitems ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
/* ===================================== Cmd_GetSavesList Prints or complete savegame filename ===================================== */ qboolean Cmd_GetSavesList( const char *s, char *completedname, int length ) { search_t *t; string matchbuf; int i, numsaves; t = FS_Search( va( "save/%s*.sav", s ), true, true ); // lookup only in gamedir if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); if( completedname && length ) Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, numsaves = 0; i < t->numfilenames; i++ ) { const char *ext = FS_FileExtension( t->filenames[i] ); if( Q_stricmp( ext, "sav" )) continue; FS_FileBase( t->filenames[i], matchbuf ); Msg( "%16s\n", matchbuf ); numsaves++; } Msg( "\n^3 %i saves found.\n", numsaves ); Mem_Free( t ); // cut shortestMatch to the amount common with s if( completedname && length ) { for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } } return true; }
char *Q_stristr( const char *string, const char *string2 ) { int c, len; if( !string || !string2 ) return NULL; c = Q_tolower( *string2 ); len = Q_strlen( string2 ); while( string ) { for( ; *string && Q_tolower( *string ) != c; string++ ); if( *string ) { if( !Q_strnicmp( string, string2, len )) break; string++; } else return NULL; } return (char *)string; }
/* =================== Key_StringToKeynum Returns a key number to be used to index keybindings[] by looking at the given string. Single ascii characters return themselves, while the K_* names are matched up. =================== */ int Key_StringToKeynum(const char *str) { const keyname_t *kn; if (!str || !str[0]) return -1; if (!str[1]) return Q_tolower(str[0]); for (kn = keynames; kn->name; kn++) { if (!Q_stricmp(str, kn->name)) return kn->keynum; } return -1; }
static qboolean Q_starcmp( const char *pattern, const char *text ) { char c, c1; const char *p = pattern, *t = text; while(( c = *p++ ) == '?' || c == '*' ) { if( c == '?' && *t++ == '\0' ) return false; } if( c == '\0' ) return true; for( c1 = (( c == '\\' ) ? *p : c ); ; ) { if( Q_tolower( *t ) == c1 && Q_stricmpext( p - 1, t )) return true; if( *t++ == '\0' ) return false; } }
/* ============= COM_LoadFileForMe ============= */ byte* COM_LoadFileForMe( const char *filename, int *pLength ) { string name; int i; if( !filename || !*filename ) { if( pLength ) *pLength = 0; return NULL; } // replace all backward slashes for( i = 0; i < Q_strlen( filename ); i++ ) { if( filename[i] == '\\' ) name[i] = '/'; else name[i] = Q_tolower( filename[i] ); } name[i] = '\0'; return FS_LoadFile( name, pLength, false ); }
/* ==================== Prompt_CompleteCommand ==================== */ void Prompt_CompleteCommand(commandPrompt_t *prompt, qboolean backslash) { inputField_t *inputLine = &prompt->inputLine; char *text, *partial, *s; int i, argc, currentArg, argnum; size_t size, len, pos; char *first, *last; genctx_t ctx; char *matches[MAX_MATCHES], *sortedMatches[MAX_MATCHES]; int numCommands, numCvars, numAliases; text = inputLine->text; size = inputLine->maxChars + 1; pos = inputLine->cursorPos; // prepend backslash if missing if (backslash) { if (inputLine->text[0] != '\\' && inputLine->text[0] != '/') { memmove(inputLine->text + 1, inputLine->text, size - 1); inputLine->text[0] = '\\'; } text++; size--; pos--; } // parse the input line into tokens Cmd_TokenizeString(text, qfalse); argc = Cmd_Argc(); // determine absolute argument number to be completed currentArg = Cmd_FindArgForOffset(pos); if (currentArg == argc - 1 && Cmd_WhiteSpaceTail()) { // start completing new argument if command line has trailing whitespace currentArg++; } // determine relative argument number to be completed argnum = 0; for (i = 0; i < currentArg; i++) { s = Cmd_Argv(i); argnum++; if (*s == ';') { // semicolon starts a new command argnum = 0; } } // get the partial argument string to be completed partial = Cmd_Argv(currentArg); if (*partial == ';') { // semicolon starts a new command currentArg++; partial = Cmd_Argv(currentArg); argnum = 0; } // generate matches memset(&ctx, 0, sizeof(ctx)); ctx.partial = partial; ctx.length = strlen(partial); ctx.argnum = currentArg; ctx.matches = matches; ctx.size = MAX_MATCHES; if (argnum) { // complete a command/cvar argument Com_Generic_c(&ctx, argnum); numCommands = numCvars = numAliases = 0; } else { // complete a command/cvar/alias name Cmd_Command_g(&ctx); numCommands = ctx.count; Cvar_Variable_g(&ctx); numCvars = ctx.count - numCommands; Cmd_Alias_g(&ctx); numAliases = ctx.count - numCvars - numCommands; } if (!ctx.count) { pos = strlen(inputLine->text); prompt->tooMany = qfalse; goto finish2; // nothing found } pos = Cmd_ArgOffset(currentArg); text += pos; size -= pos; // append whitespace since Cmd_TokenizeString eats it if (currentArg == argc && Cmd_WhiteSpaceTail()) { *text++ = ' '; pos++; size--; } if (ctx.count == 1) { // we have finished completion! s = Cmd_RawArgsFrom(currentArg + 1); if (needs_quotes(matches[0])) { pos += Q_concat(text, size, "\"", matches[0], "\" ", s, NULL); } else { pos += Q_concat(text, size, matches[0], " ", s, NULL); } pos++; prompt->tooMany = qfalse; goto finish1; } if (ctx.count > com_completion_treshold->integer && !prompt->tooMany) { prompt->printf("Press TAB again to display all %d possibilities.\n", ctx.count); pos = strlen(inputLine->text); prompt->tooMany = qtrue; goto finish1; } prompt->tooMany = qfalse; // sort matches alphabethically for (i = 0; i < ctx.count; i++) { sortedMatches[i] = matches[i]; } qsort(sortedMatches, ctx.count, sizeof(sortedMatches[0]), ctx.ignorecase ? SortStricmp : SortStrcmp); // copy matching part first = sortedMatches[0]; last = sortedMatches[ctx.count - 1]; len = 0; do { if (*first != *last) { if (!ctx.ignorecase || Q_tolower(*first) != Q_tolower(*last)) { break; } } text[len++] = *first; if (len == size - 1) { break; } first++; last++; } while (*first); text[len] = 0; pos += len; size -= len; // copy trailing arguments if (currentArg + 1 < argc) { s = Cmd_RawArgsFrom(currentArg + 1); pos += Q_concat(text + len, size, " ", s, NULL); } pos++; prompt->printf("]\\%s\n", Cmd_ArgsFrom(0)); if (argnum) { goto multi; } switch (com_completion_mode->integer) { case 0: // print in solid list for (i = 0; i < ctx.count; i++) { prompt->printf("%s\n", sortedMatches[i]); } break; case 1: multi: // print in multiple columns Prompt_ShowMatches(prompt, sortedMatches, 0, ctx.count); break; case 2: default: // resort matches by type and print in multiple columns Prompt_ShowIndividualMatches(prompt, matches, numCommands, numAliases, numCvars); break; } finish1: // free matches for (i = 0; i < ctx.count; i++) { Z_Free(matches[i]); } finish2: // move cursor if (pos >= inputLine->maxChars) { pos = inputLine->maxChars - 1; } inputLine->cursorPos = pos; }
//----------------------------------------------------------------------------- // Purpose: Take a NULL terminated sentence, and parse any commands contained in // {}. The string is rewritten in place with those commands removed. // // Input : *pSentenceData - sentence data to be modified in place // sentenceIndex - global sentence table index for any data that is // parsed out //----------------------------------------------------------------------------- void VOX_ParseLineCommands( char *pSentenceData, int sentenceIndex ) { char tempBuffer[512]; char *pNext, *pStart; int length, tempBufferPos = 0; if( !pSentenceData ) return; pStart = pSentenceData; while( *pSentenceData ) { pNext = ScanForwardUntil( pSentenceData, '{' ); // find length of "good" portion of the string (not a {} command) length = pNext - pSentenceData; if( tempBufferPos + length > sizeof( tempBuffer )) { MsgDev( D_ERROR, "sentence too long!\n" ); return; } // Copy good string to temp buffer Q_memcpy( tempBuffer + tempBufferPos, pSentenceData, length ); // move the copy position tempBufferPos += length; pSentenceData = pNext; // skip ahead of the opening brace if( *pSentenceData ) pSentenceData++; // skip whitespace while( *pSentenceData && *pSentenceData <= 32 ) pSentenceData++; // simple comparison of string commands: switch( Q_tolower( *pSentenceData )) { case 'l': // all commands starting with the letter 'l' here if( !Q_strnicmp( pSentenceData, "len", 3 )) { g_Sentences[sentenceIndex].length = Q_atof( pSentenceData + 3 ); } break; case 0: default: break; } pSentenceData = ScanForwardUntil( pSentenceData, '}' ); // skip the closing brace if( *pSentenceData ) pSentenceData++; // skip trailing whitespace while( *pSentenceData && *pSentenceData <= 32 ) pSentenceData++; } if( tempBufferPos < sizeof( tempBuffer )) { // terminate cleaned up copy tempBuffer[tempBufferPos] = 0; // copy it over the original data Q_strcpy( pStart, tempBuffer ); } }
/* ===================================== Cmd_GetMapList Prints or complete map filename ===================================== */ qboolean Cmd_GetMapList( const char *s, char *completedname, int length ) { search_t *t; file_t *f; string message; string matchbuf; byte buf[MAX_SYSPATH]; // 1 kb int i, nummaps; t = FS_Search( va( "maps/%s*.bsp", s ), true, con_gamemaps->integer ); if( !t ) return false; FS_FileBase( t->filenames[0], matchbuf ); Q_strncpy( completedname, matchbuf, length ); if( t->numfilenames == 1 ) return true; for( i = 0, nummaps = 0; i < t->numfilenames; i++ ) { char entfilename[CS_SIZE]; int ver = -1, mapver = -1, lumpofs = 0, lumplen = 0; const char *ext = FS_FileExtension( t->filenames[i] ); char *ents = NULL, *pfile; qboolean paranoia = false; qboolean gearbox = false; if( Q_stricmp( ext, "bsp" )) continue; Q_strncpy( message, "^1error^7", sizeof( message )); f = FS_Open( t->filenames[i], "rb", con_gamemaps->integer ); if( f ) { dheader_t *header; dextrahdr_t *hdrext; Q_memset( buf, 0, sizeof( buf )); FS_Read( f, buf, sizeof( buf )); header = (dheader_t *)buf; ver = header->version; switch( ver ) { case Q1BSP_VERSION: case HLBSP_VERSION: case XTBSP_VERSION: if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 && !(header->lumps[LUMP_ENTITIES].filelen % sizeof(dplane_t))) { lumpofs = header->lumps[LUMP_PLANES].fileofs; lumplen = header->lumps[LUMP_PLANES].filelen; gearbox = true; } else { lumpofs = header->lumps[LUMP_ENTITIES].fileofs; lumplen = header->lumps[LUMP_ENTITIES].filelen; gearbox = false; } break; } if( ver == XTBSP_VERSION ) hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader31_t )); else hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t )); if( hdrext->id == IDEXTRAHEADER && hdrext->version == EXTRA_VERSION ) paranoia = true; Q_strncpy( entfilename, t->filenames[i], sizeof( entfilename )); FS_StripExtension( entfilename ); FS_DefaultExtension( entfilename, ".ent" ); ents = FS_LoadFile( entfilename, NULL, true ); if( !ents && lumplen >= 10 ) { FS_Seek( f, lumpofs, SEEK_SET ); ents = (char *)Mem_Alloc( host.mempool, lumplen + 1 ); FS_Read( f, ents, lumplen ); } if( ents ) { // if there are entities to parse, a missing message key just // means there is no title, so clear the message string now char token[2048]; message[0] = 0; pfile = ents; while(( pfile = COM_ParseFile( pfile, token )) != NULL ) { if( !Q_strcmp( token, "{" )) continue; else if(!Q_strcmp( token, "}" )) break; else if(!Q_strcmp( token, "message" )) { // get the message contents pfile = COM_ParseFile( pfile, message ); } else if(!Q_strcmp( token, "mapversion" )) { // get the message contents pfile = COM_ParseFile( pfile, token ); mapver = Q_atoi( token ); } } Mem_Free( ents ); } } if( f ) FS_Close(f); FS_FileBase( t->filenames[i], matchbuf ); switch( ver ) { case Q1BSP_VERSION: if( mapver == 220 ) Q_strncpy( buf, "Half-Life Alpha", sizeof( buf )); else Q_strncpy( buf, "Quake", sizeof( buf )); break; case HLBSP_VERSION: if( gearbox ) Q_strncpy( buf, "Blue-Shift", sizeof( buf )); else if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf )); else Q_strncpy( buf, "Half-Life", sizeof( buf )); break; case XTBSP_VERSION: if( paranoia ) Q_strncpy( buf, "Paranoia 2", sizeof( buf )); else Q_strncpy( buf, "Xash3D", sizeof( buf )); break; default: Q_strncpy( buf, "??", sizeof( buf )); break; } Msg( "%16s (%s) ^3%s^7\n", matchbuf, buf, message ); nummaps++; } Msg( "\n^3 %i maps found.\n", nummaps ); Mem_Free( t ); // cut shortestMatch to the amount common with s for( i = 0; matchbuf[i]; i++ ) { if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) completedname[i] = 0; } return true; }