/* =============== SVC_RemoteCommand An rcon packet arrived from the network. Shift down the remaining args Redirect all printfs =============== */ static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc. // (OOB messages are the bottleneck here) #define SV_OUTPUTBUF_LENGTH (1024 - 16) char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; static unsigned int lasttime = 0; char *cmd_aux; // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534 time = Com_Milliseconds(); if ( (unsigned)( time - lasttime ) < 500u ) { return; } lasttime = time; if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { valid = qfalse; Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } else { valid = qtrue; Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } // start redirecting all print outputs to the packet svs.redirectAddress = from; Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect); if ( !strlen( sv_rconPassword->string ) ) { Com_Printf ("No rconpassword set on the server.\n"); } else if ( !valid ) { Com_Printf ("Bad rconpassword.\n"); } else { remaining[0] = 0; // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 // get the command directly, "rcon <pass> <command>" to avoid quoting issues // extract the command by walking // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing cmd_aux = Cmd_Cmd(); cmd_aux+=4; while(cmd_aux[0]==' ') cmd_aux++; while(cmd_aux[0] && cmd_aux[0]!=' ') // password cmd_aux++; while(cmd_aux[0]==' ') cmd_aux++; Q_strcat( remaining, sizeof(remaining), cmd_aux); Cmd_ExecuteString (remaining); } Com_EndRedirect (); }
/* =================== Key_Bind_f =================== */ static void Key_Bind_f(void) { int c, b; c = Cmd_Argc(); if (c < 2) { Com_Printf("bind <key> [command] : attach a command to a key\n"); return; } b = Key_StringToKeynum(Cmd_Argv(1)); if (b == -1) { Com_Printf("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } if (c == 2) { if (keybindings[b]) Com_Printf("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b]); else Com_Printf("\"%s\" is not bound\n", Cmd_Argv(1)); return; } // copy the rest of the command line Key_SetBinding(b, Cmd_ArgsFrom(2)); }
/* ================== SV_ConTell_f ================== */ static void SV_ConTell_f(void) { char *p; char text[1024]; client_t *cl; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() < 3 ) { Com_Printf ("Usage: tell <client number> <text>\n"); return; } cl = SV_GetPlayerByNum(); if ( !cl ) { return; } strcpy (text, "console_tell: "); p = Cmd_ArgsFrom(2); if ( *p == '"' ) { p++; p[strlen(p)-1] = 0; } strcat(text, p); SV_SendServerCommand(cl, "chat \"%s\"", text); }
/* ================== SV_StartServerDemo_f Record a server-side demo for given player/slot. The demo will be called "YYYY-MM-DD_hh-mm-ss_playername_id.urtdemo", in the "demos" directory under your game directory. Note that "startserverdemo all" will start demos for all players currently in the server. Players who join later require a new "startserverdemo" command. If you are already recording demos for some players, another "startserverdemo all" will start new demos only for players not already recording. Note that bots will never be recorded, not even if "all" is given. The server-side demos will stop when "stopserverdemo" is issued or when the server restarts for any reason (such as a new map loading). ================== */ static void SV_StartServerDemo_f(void) { client_t *client; Com_DPrintf("SV_StartServerDemo_f\n"); if (!com_sv_running->integer) { Com_Printf("startserverdemo: Server not running\n"); return; } if (Cmd_Argc() < 2) { Com_Printf("Usage: startserverdemo <player-or-all> <optional demo name>\n"); return; } client = SV_BetterGetPlayerByHandle(Cmd_Argv(1)); if (!Q_stricmp(Cmd_Argv(1), "all")) { if (client) { Com_Printf("startserverdemo: Player 'all' ignored, starting all demos instead\n"); } SV_StartRecordAll(); } else if (client) { if (Cmd_Argc() > 2) { SV_StartRecordOne(client, Cmd_ArgsFrom(2)); } else { SV_StartRecordOne(client, NULL); } } else { Com_Printf("startserverdemo: No player with that handle/in that slot\n"); } }
/* ================== SV_ForceName_f Sets a user's name ================== */ static void SV_ForceName_f( void ) { client_t *cl; const char *name; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() >= 2 ) { cl = SV_GetPlayerByNum(); if ( !cl ) { return; } if ( Cmd_Argc() == 2 ) { Com_Printf ("forcename: %s: %s\n",Cmd_Argv(1),cl->name); return; } else { name = Cmd_ArgsFrom(2); cl->forcename = 2; Q_strncpyz( cl->name, name, sizeof(cl->name) ); SV_UserinfoChanged( cl ); VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients ); Com_Printf ("forcename: %s: %s\n",Cmd_Argv(1),cl->name); return; } } Com_Printf ("Usage: forcename <client number> [<name>]\n"); return; }
/* ================== SV_StartServerDemo_f Record a server-side demo for given player/slot. The demo will be called "YYYY-MM-DD_hh-mm-ss_playername_id.urtdemo", in the "demos" directory under your game directory. Note that "startserverdemo all" will start demos for all players currently in the server. Players who join later require a new "startserverdemo" command. If you are already recording demos for some players, another "startserverdemo all" will start new demos only for players not already recording. Note that bots will never be recorded, not even if "all" is given. The server-side demos will stop when "stopserverdemo" is issued or when the server restarts for any reason (such as a new map loading). ================== */ static void SV_StartServerDemo_f(void) { client_t *client; Com_DPrintf("SV_StartServerDemo_f\n"); if (!com_sv_running->integer) { Com_Printf("startserverdemo: Server not running\n"); return; } if (Cmd_Argc() < 2) { Com_Printf("Usage: startserverdemo <client-or-all> [<optional-demo-name>]\n"); return; } if (!Q_stricmp(Cmd_Argv(1), "all")) { SV_StartRecordAll(); } else { client = SV_GetPlayerByHandle(); if (!client) { return; } if (Cmd_Argc() > 2) { SV_StartRecordOne(client, Cmd_ArgsFrom(2)); } else { SV_StartRecordOne(client, NULL); } } }
/* ================== SV_ConTell_f Based on Urban Terror implementation ================== */ static void SV_ConTell_f(void) { char *p; char text[MAX_STRING_CHARS-18];// OK? client_t *cl; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() < 3 ) { Com_Printf ("Usage: tell <client number> <text>\n"); return; } cl = SV_GetPlayerByNum(); if ( !cl ) { return; } strcpy (text, "^3private:^7 "); p = Cmd_ArgsFrom(2); if ( *p == '"' ) { p++; p[strlen(p)-1] = 0; } strcat(text, p); SV_SendServerCommand(cl, "print \"%s\n\"", SV_ConvertNewlines((char *)text)); }
/* ===================== CL_ConfigstringModified ===================== */ void CL_ConfigstringModified( void ) { char *old, *s; int i, index; char *dup; gameState_t oldGs; int len; index = atoi( Cmd_Argv( 1 ) ); if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { Com_Error( ERR_DROP, "CL_ConfigstringModified: bad index %i", index ); } // s = Cmd_Argv(2); // get everything after "cs <num>" s = Cmd_ArgsFrom( 2 ); old = cl.gameState.stringData + cl.gameState.stringOffsets[ index ]; if ( !strcmp( old, s ) ) { return; // unchanged } // build the new gameState_t oldGs = cl.gameState; memset( &cl.gameState, 0, sizeof( cl.gameState ) ); // leave the first 0 for uninitialized strings cl.gameState.dataCount = 1; for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[0] ) { continue; // leave with the default empty string } len = strlen( dup ); if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) { Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" ); } // append it to the gameState string buffer cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount; memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 ); cl.gameState.dataCount += len + 1; } if ( index == CS_SYSTEMINFO ) { // parse serverId and other cvars CL_SystemInfoChanged(); } }
/* =============== Cmd_ExecFile =============== */ static void Cmd_ExecFile( char *f ) { int i; COM_Compress (f); Cvar_Get( "arg_all", Cmd_ArgsFrom(2), CVAR_TEMP | CVAR_ROM | CVAR_USER_CREATED, "" ); Cvar_Set( "arg_all", Cmd_ArgsFrom(2) ); Cvar_Get( "arg_count", va( "%i", Cmd_Argc() - 2 ), CVAR_TEMP | CVAR_ROM | CVAR_USER_CREATED, "" ); Cvar_Set( "arg_count", va( "%i", Cmd_Argc() - 2 ) ); for (i = Cmd_Argc() - 2; i; i--) { Cvar_Get( va("arg_%i", i), Cmd_Argv( i + 1 ), CVAR_TEMP | CVAR_ROM | CVAR_USER_CREATED, "" ); Cvar_Set( va("arg_%i", i), Cmd_Argv( i + 1 ) ); } Cbuf_InsertText (f); }
/* =============== Cmd_Delay_f Delays a comand =============== */ void Cmd_Delay_f (void) { int i, delay, type; char *raw_delay; qboolean availiable_cmd = qfalse; // Check if the call is valid if(Cmd_Argc () < 2) { Com_Printf ("delay <delay in milliseconds> <command>\ndelay <delay in frames>f <command>\nexecutes <command> after the delay\n"); return; } raw_delay = Cmd_Argv(1); delay = atoi(raw_delay); if(delay < 1) { Com_Printf ("delay: the delay must be a positive integer"); return; } //search for an unused slot for(i=0; (i<MAX_DELAYED_COMMANDS); i++) { if(delayed_cmd[i].delay == CMD_DELAY_UNUSED) { availiable_cmd = qtrue; break; } } if(!availiable_cmd) { Com_Printf ("WARNING: Maximum amount of delayed commands reached."); return; } int lastchar = strlen( raw_delay ) - 1; if(raw_delay[ lastchar ] == 'f' ) { delay += CMD_DELAY_FRAME_FIRE; type = CMD_DELAY_FRAME; }else{ type = CMD_DELAY_MSEC; delay += Sys_Milliseconds(); } delayed_cmd[i].delay = delay; delayed_cmd[i].type = type; Q_strncpyz(delayed_cmd[i].text, Cmd_ArgsFrom(2), MAX_CMD_LINE); }
/* ================== SV_Map_f Restart the server on a different map ================== */ static void SV_Map_f( void ) { char *cmd; char *map; const char *layouts; char mapname[ MAX_QPATH ]; qboolean cheat; char expanded[ MAX_QPATH ]; char layout[ MAX_CVAR_VALUE_STRING ]; map = Cmd_Argv( 1 ); if ( !map ) { return; } // make sure the level exists before trying to change, so that // a typo at the server console won't end the game Com_sprintf( expanded, sizeof( expanded ), "maps/%s.bsp", map ); if ( FS_ReadFile( expanded, NULL ) == -1 ) { Com_Printf(_( "Can't find map %s\n"), expanded ); return; } // layout(s) - note that ArgsFrom adds quoting which we don't want here // Also, if empty, don't override layouts = Cmd_UnquoteString( Cmd_ArgsFrom( 2 ) ); if ( *layouts ) { Cvar_Set( "g_layouts", layouts ); } cheat = !Q_stricmp( Cmd_Argv( 0 ), "devmap" ); // save the map name here cause on a map restart we reload the q3config.cfg // and thus nuke the arguments of the map command Q_strncpyz( mapname, map, sizeof( mapname ) ); // start up the map SV_SpawnServer( mapname ); // set the cheat value // if the level was started with "map <levelname>", then // cheats will not be allowed. If started with "devmap <levelname>" // then cheats will be allowed Cvar_Set( "sv_cheats", cheat ? "1" : "0" ); }
/* ======================================================================================================================================= Cvar_Set_f Allows setting and defining of arbitrary cvars from console, even if they weren't declared in C code. ======================================================================================================================================= */ void Cvar_Set_f(void) { int c; char *cmd; cvar_t *v; c = Cmd_Argc(); cmd = Cmd_Argv(0); if (c < 2) { Com_Printf("usage: %s <variable> <value>\n", cmd); return; } if (c == 2) { Cvar_Print_f(); return; } v = Cvar_Set2(Cmd_Argv(1), Cmd_ArgsFrom(2), qfalse); if (!v) { return; } switch (cmd[3]) { case 'a': if (!(v->flags & CVAR_ARCHIVE)) { v->flags |= CVAR_ARCHIVE; cvar_modifiedFlags |= CVAR_ARCHIVE; } break; case 'u': if (!(v->flags & CVAR_USERINFO)) { v->flags |= CVAR_USERINFO; cvar_modifiedFlags |= CVAR_USERINFO; } break; case 's': if (!(v->flags & CVAR_SERVERINFO)) { v->flags |= CVAR_SERVERINFO; cvar_modifiedFlags |= CVAR_SERVERINFO; } break; } }
static void SV_ConBig_f(void) { char *p; char text[1024]; client_t *cl; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() < 3 ) { Com_Printf ("Usage: big <clientid> <text>\n"); return; } cl = SV_GetPlayerByNum(); if (atoi(Cmd_Argv(1)) < 0) { cl = NULL; } // if (atoi(Cmd_Argv(1))) { // Com_Printf ("Hi1 -1\n"); //// Com_Printf ("Hi2 -1\n"); // if ( !cl ) { // return; // } //// Com_Printf ("Hi3 -1\n"); // } strcpy (text, "^3"); p = Cmd_ArgsFrom(2); if ( *p == '"' ) { p++; p[strlen(p)-1] = 0; } strcat(text, p); SV_SendServerCommand(cl, "cp \"" S_COLOR_WHITE "%s\n\"", text); }
/* ============ Cmd_RunAlias_f ============ */ void Cmd_RunAlias_f(void) { cmd_alias_t *alias; char *name = Cmd_Argv(0); char *args = Cmd_ArgsFrom(1); // Find existing alias for (alias = cmd_aliases; alias; alias=alias->next) { if (!Q_stricmp( name, alias->name )) break; } if (!alias) Com_Error(ERR_FATAL, "Alias: Alias %s doesn't exist", name); Cbuf_InsertText(va("%s %s", alias->exec, args)); }
static void Com_Setenv_f(void) { int argc = Cmd_Argc(); if (argc > 2) { Q_setenv(Cmd_Argv(1), Cmd_ArgsFrom(2)); } else if (argc == 2) { char *env = getenv(Cmd_Argv(1)); if (env) { Com_Printf("%s=%s\n", Cmd_Argv(1), env); } else { Com_Printf("%s undefined\n", Cmd_Argv(1)); } } else { Com_Printf("Usage: %s <name> [value]\n", Cmd_Argv(0)); } }
/* ============ Cvar_Set_f Allows setting and defining of arbitrary cvars from console, even if they weren't declared in C code. ============ */ void Cvar_Set_f( void ) { int c, flag; char *cmd; cvar_t *v; c = Cmd_Argc(); cmd = Cmd_Argv(0); if ( c < 2 ) { Com_Printf ("usage: %s <variable> <value>\n", cmd); return; } if ( c == 2 ) { Cvar_Print_f(); return; } v = Cvar_Set2 (Cmd_Argv(1), Cmd_ArgsFrom(2), qfalse); if( !v ) { return; } // don't make these old vars archive even if the client's old autogen told us to if( !Q_stricmp( Cmd_Argv(1), "r_mode" ) || !Q_stricmp( Cmd_Argv(1), "r_customheight" ) || !Q_stricmp( Cmd_Argv(1), "r_customwidth" ) || !Q_stricmp( Cmd_Argv(1), "r_custompixelAspect" ) ) return; switch( cmd[3] ) { default: return; case 'u': flag = CVAR_USERINFO; break; case 's': flag = CVAR_SERVERINFO; break; case 'a': case '\0': flag = CVAR_ARCHIVE; break; } v->flags |= flag; cvar_modifiedFlags |= flag; }
static void Parse_Bitmap(menuFrameWork_t *menu) { static const cmd_option_t o_bitmap[] = { { "s:", "status" }, { "N:", "altname" }, { NULL } }; menuBitmap_t *b; char *status = NULL, *altname = NULL; int c; while ((c = Cmd_ParseOptions(o_bitmap)) != -1) { switch (c) { case 's': status = cmd_optarg; break; case 'N': altname = cmd_optarg; break; default: return; } } if (Cmd_Argc() - cmd_optind < 2) { Com_Printf("Usage: %s <name> <command>\n", Cmd_Argv(0)); return; } if (!altname) altname = va("%s_sel", Cmd_Argv(cmd_optind)); b = UI_Mallocz(sizeof(*b)); b->generic.type = MTYPE_BITMAP; b->generic.activate = Activate; b->generic.status = UI_CopyString(status); b->cmd = UI_CopyString(Cmd_ArgsFrom(cmd_optind + 1)); b->pics[0] = R_RegisterPic(Cmd_Argv(cmd_optind)); b->pics[1] = R_RegisterPic(altname); R_GetPicSize(&b->generic.width, &b->generic.height, b->pics[0]); Menu_AddItem(menu, b); }
qboolean demoCutConfigstringModified(clientActive_t *clCut) { char *old, *s; int i, index; char *dup; gameState_t oldGs; int len; index = atoi(Cmd_Argv(1)); if (index < 0 || index >= MAX_CONFIGSTRINGS) { Com_Printf("demoCutConfigstringModified: bad index %i", index); return qtrue; } // get everything after "cs <num>" s = Cmd_ArgsFrom(2); old = clCut->gameState.stringData + clCut->gameState.stringOffsets[index]; if (!strcmp(old, s)) { return qtrue; // unchanged } // build the new gameState_t oldGs = clCut->gameState; Com_Memset(&clCut->gameState, 0, sizeof(clCut->gameState)); // leave the first 0 for uninitialized strings clCut->gameState.dataCount = 1; for (i = 0; i < MAX_CONFIGSTRINGS; i++) { if (i == index) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[i]; } if (!dup[0]) { continue; // leave with the default empty string } len = strlen(dup); if (len + 1 + clCut->gameState.dataCount > MAX_GAMESTATE_CHARS) { Com_Printf("MAX_GAMESTATE_CHARS exceeded"); return qfalse; } // append it to the gameState string buffer clCut->gameState.stringOffsets[i] = clCut->gameState.dataCount; Com_Memcpy(clCut->gameState.stringData + clCut->gameState.dataCount, dup, len + 1); clCut->gameState.dataCount += len + 1; } return qtrue; }
static void Parse_Spin(menuFrameWork_t *menu, menuType_t type) { menuSpinControl_t *s; int c, i, numItems; char *status = NULL; while ((c = Cmd_ParseOptions(o_common)) != -1) { switch (c) { case 's': status = cmd_optarg; break; default: return; } } numItems = Cmd_Argc() - (cmd_optind + 2); if (numItems < 1) { Com_Printf("Usage: %s <name> <cvar> <desc1> [...]\n", Cmd_Argv(0)); return; } s = UI_Mallocz(sizeof(*s)); s->generic.type = type; s->generic.name = UI_CopyString(Cmd_Argv(cmd_optind)); s->generic.status = UI_CopyString(status); s->cvar = Cvar_WeakGet(Cmd_Argv(cmd_optind + 1)); cmd_optind += 2; if (strchr(Cmd_ArgsFrom(cmd_optind), '$')) { long_args_hack(s, numItems); } else { s->itemnames = UI_Mallocz(sizeof(char *) * (numItems + 1)); for (i = 0; i < numItems; i++) { s->itemnames[i] = UI_CopyString(Cmd_Argv(cmd_optind + i)); } s->numItems = numItems; } Menu_AddItem(menu, s); }
static void Parse_Bind(menuFrameWork_t *menu) { static const cmd_option_t o_bind[] = { { "s:", "status" }, { "S:", "altstatus" }, { NULL } }; menuKeybind_t *k; char *status = "Press Enter to change, Backspace to clear"; char *altstatus = "Press the desired key, Escape to cancel"; int c; while ((c = Cmd_ParseOptions(o_bind)) != -1) { switch (c) { case 's': status = cmd_optarg; break; case 'S': altstatus = cmd_optarg; break; default: return; } } if (Cmd_Argc() - cmd_optind < 2) { Com_Printf("Usage: %s <name> <command>\n", Cmd_Argv(0)); return; } k = UI_Mallocz(sizeof(*k)); k->generic.type = MTYPE_KEYBIND; k->generic.name = UI_CopyString(Cmd_Argv(cmd_optind)); k->generic.uiFlags = UI_CENTER; k->generic.status = UI_CopyString(status); k->cmd = UI_CopyString(Cmd_ArgsFrom(cmd_optind + 1)); k->altstatus = UI_CopyString(altstatus); Menu_AddItem(menu, k); }
static void Parse_Action(menuFrameWork_t *menu) { static const cmd_option_t o_action[] = { { "a", "align" }, { "s:", "status" }, { NULL } }; menuAction_t *a; int uiFlags = UI_CENTER; char *status = NULL; int c; while ((c = Cmd_ParseOptions(o_action)) != -1) { switch (c) { case 'a': uiFlags = UI_LEFT | UI_ALTCOLOR; break; case 's': status = cmd_optarg; break; default: return; } } if (Cmd_Argc() - cmd_optind < 2) { Com_Printf("Usage: %s <name> <command>\n", Cmd_Argv(0)); return; } a = UI_Mallocz(sizeof(*a)); a->generic.type = MTYPE_ACTION; a->generic.name = UI_CopyString(Cmd_Argv(cmd_optind)); a->generic.activate = Activate; a->generic.uiFlags = uiFlags; a->generic.status = UI_CopyString(status); a->cmd = UI_CopyString(Cmd_ArgsFrom(cmd_optind + 1)); Menu_AddItem(menu, a); }
static void CLT3_ConfigstringModified() { int index = String::Atoi( Cmd_Argv( 1 ) ); // get everything after "cs <num>" const char* s = Cmd_ArgsFrom( 2 ); if ( GGameType & GAME_Quake3 ) { if ( index < 0 || index >= MAX_CONFIGSTRINGS_Q3 ) { common->Error( "configstring > MAX_CONFIGSTRINGS_Q3" ); } const char* old = cl.q3_gameState.stringData + cl.q3_gameState.stringOffsets[ index ]; if ( !String::Cmp( old, s ) ) { return; // unchanged } // build the new q3gameState_t q3gameState_t oldGs = cl.q3_gameState; Com_Memset( &cl.q3_gameState, 0, sizeof ( cl.q3_gameState ) ); // leave the first 0 for uninitialized strings cl.q3_gameState.dataCount = 1; for ( int i = 0; i < MAX_CONFIGSTRINGS_Q3; i++ ) { const char* dup; if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[ 0 ] ) { continue; // leave with the default empty string } int len = String::Length( dup ); if ( len + 1 + cl.q3_gameState.dataCount > MAX_GAMESTATE_CHARS_Q3 ) { common->Error( "MAX_GAMESTATE_CHARS_Q3 exceeded" ); } // append it to the gameState string buffer cl.q3_gameState.stringOffsets[ i ] = cl.q3_gameState.dataCount; Com_Memcpy( cl.q3_gameState.stringData + cl.q3_gameState.dataCount, dup, len + 1 ); cl.q3_gameState.dataCount += len + 1; } if ( index == Q3CS_SYSTEMINFO ) { // parse serverId and other cvars CLT3_SystemInfoChanged(); } } else if ( GGameType & GAME_WolfSP ) { if ( index < 0 || index >= MAX_CONFIGSTRINGS_WS ) { common->Error( "configstring > MAX_CONFIGSTRINGS_WS" ); } const char* old = cl.ws_gameState.stringData + cl.ws_gameState.stringOffsets[ index ]; if ( !String::Cmp( old, s ) ) { return; // unchanged } // build the new wsgameState_t wsgameState_t oldGs = cl.ws_gameState; memset( &cl.ws_gameState, 0, sizeof ( cl.ws_gameState ) ); // leave the first 0 for uninitialized strings cl.ws_gameState.dataCount = 1; for ( int i = 0; i < MAX_CONFIGSTRINGS_WS; i++ ) { const char* dup; if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[ 0 ] ) { continue; // leave with the default empty string } int len = String::Length( dup ); if ( len + 1 + cl.ws_gameState.dataCount > MAX_GAMESTATE_CHARS_Q3 ) { common->Error( "MAX_GAMESTATE_CHARS_Q3 exceeded" ); } // append it to the gameState string buffer cl.ws_gameState.stringOffsets[ i ] = cl.ws_gameState.dataCount; memcpy( cl.ws_gameState.stringData + cl.ws_gameState.dataCount, dup, len + 1 ); cl.ws_gameState.dataCount += len + 1; } if ( index == Q3CS_SYSTEMINFO ) { // parse serverId and other cvars CLT3_SystemInfoChanged(); } } else if ( GGameType & GAME_WolfMP ) { if ( index < 0 || index >= MAX_CONFIGSTRINGS_WM ) { common->Error( "configstring > MAX_CONFIGSTRINGS_WM" ); } const char* old = cl.wm_gameState.stringData + cl.wm_gameState.stringOffsets[ index ]; if ( !String::Cmp( old, s ) ) { return; // unchanged } // build the new wmgameState_t wmgameState_t oldGs = cl.wm_gameState; memset( &cl.wm_gameState, 0, sizeof ( cl.wm_gameState ) ); // leave the first 0 for uninitialized strings cl.wm_gameState.dataCount = 1; for ( int i = 0; i < MAX_CONFIGSTRINGS_WM; i++ ) { const char* dup; if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[ 0 ] ) { continue; // leave with the default empty string } int len = String::Length( dup ); if ( len + 1 + cl.wm_gameState.dataCount > MAX_GAMESTATE_CHARS_Q3 ) { common->Error( "MAX_GAMESTATE_CHARS_Q3 exceeded" ); } // append it to the gameState string buffer cl.wm_gameState.stringOffsets[ i ] = cl.wm_gameState.dataCount; memcpy( cl.wm_gameState.stringData + cl.wm_gameState.dataCount, dup, len + 1 ); cl.wm_gameState.dataCount += len + 1; } if ( index == Q3CS_SYSTEMINFO ) { // parse serverId and other cvars CLT3_SystemInfoChanged(); } } else { if ( index < 0 || index >= MAX_CONFIGSTRINGS_ET ) { common->Error( "configstring > MAX_CONFIGSTRINGS_ET" ); } const char* old = cl.et_gameState.stringData + cl.et_gameState.stringOffsets[ index ]; if ( !String::Cmp( old, s ) ) { return; // unchanged } // build the new etgameState_t etgameState_t oldGs = cl.et_gameState; memset( &cl.et_gameState, 0, sizeof ( cl.et_gameState ) ); // leave the first 0 for uninitialized strings cl.et_gameState.dataCount = 1; for ( int i = 0; i < MAX_CONFIGSTRINGS_ET; i++ ) { const char* dup; if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[ 0 ] ) { continue; // leave with the default empty string } int len = String::Length( dup ); if ( len + 1 + cl.et_gameState.dataCount > MAX_GAMESTATE_CHARS_Q3 ) { common->Error( "MAX_GAMESTATE_CHARS_Q3 exceeded" ); } // append it to the gameState string buffer cl.et_gameState.stringOffsets[ i ] = cl.et_gameState.dataCount; memcpy( cl.et_gameState.stringData + cl.et_gameState.dataCount, dup, len + 1 ); cl.et_gameState.dataCount += len + 1; } if ( index == Q3CS_SYSTEMINFO ) { // parse serverId and other cvars CLT3_SystemInfoChanged(); } } }
void demoConvert( const char *oldName, const char *newBaseName, qboolean smoothen ) { fileHandle_t oldHandle = 0; fileHandle_t newHandle = 0; int temp; int oldSize; int msgSequence; msg_t oldMsg; byte oldData[ MAX_MSGLEN ]; int oldTime, nextTime, fullTime; int clientNum; demoFrame_t *workFrame; int parseEntitiesNum = 0; demoConvert_t *convert; char bigConfigString[BIG_INFO_STRING]; int bigConfigNumber; const char *s; clSnapshot_t *oldSnap = 0; clSnapshot_t *newSnap; int levelCount = 0; char newName[MAX_OSPATH]; oldSize = FS_FOpenFileRead( oldName, &oldHandle, qtrue ); if (!oldHandle) { Com_Printf("Failed to open %s for conversion.", oldName); return; } /* Alloc some memory */ convert = Z_Malloc( sizeof( demoConvert_t) ); /* Initialize the first workframe's strings */ while (oldSize > 0) { MSG_Init( &oldMsg, oldData, sizeof( oldData ) ); /* Read the sequence number */ if (FS_Read( &convert->messageNum, 4, oldHandle) != 4) goto conversionerror; convert->messageNum = LittleLong( convert->messageNum ); oldSize -= 4; /* Read the message size */ if (FS_Read( &oldMsg.cursize,4, oldHandle) != 4) goto conversionerror; oldSize -= 4; oldMsg.cursize = LittleLong( oldMsg.cursize ); /* Negative size signals end of demo */ if (oldMsg.cursize < 0) break; if ( oldMsg.cursize > oldMsg.maxsize ) goto conversionerror; /* Read the actual message */ if (FS_Read( oldMsg.data, oldMsg.cursize, oldHandle ) != oldMsg.cursize) goto conversionerror; oldSize -= oldMsg.cursize; // init the bitstream MSG_BeginReading( &oldMsg ); // Skip the reliable sequence acknowledge number MSG_ReadLong( &oldMsg ); // // parse the message // while ( 1 ) { byte cmd; if ( oldMsg.readcount > oldMsg.cursize ) { Com_Printf ("Demo conversion, read past end of server message.\n"); goto conversionerror; } cmd = MSG_ReadByte( &oldMsg ); if ( cmd == svc_EOF) { break; } workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ]; // other commands switch ( cmd ) { default: Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n"); break; case svc_nop: break; case svc_serverCommand: temp = MSG_ReadLong( &oldMsg ); s = MSG_ReadString( &oldMsg ); if (temp<=msgSequence) break; // Com_Printf( " server command %s\n", s ); msgSequence = temp; Cmd_TokenizeString( s ); if ( !Q_stricmp( Cmd_Argv(0), "bcs0" ) ) { bigConfigNumber = atoi( Cmd_Argv(1) ); Q_strncpyz( bigConfigString, Cmd_Argv(2), sizeof( bigConfigString )); break; } if ( !Q_stricmp( Cmd_Argv(0), "bcs1" ) ) { Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2)); break; } if ( !Q_stricmp( Cmd_Argv(0), "bcs2" ) ) { Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2)); demoFrameAddString( &workFrame->string, bigConfigNumber, bigConfigString ); break; } if ( !Q_stricmp( Cmd_Argv(0), "cs" ) ) { int num = atoi( Cmd_Argv(1) ); s = Cmd_ArgsFrom( 2 ); demoFrameAddString( &workFrame->string, num, Cmd_ArgsFrom( 2 ) ); break; } if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { int len = strlen( s ) + 1; char *dst; if (workFrame->commandUsed + len + 1 > sizeof( workFrame->commandData)) { Com_Printf("Overflowed state command data.\n"); goto conversionerror; } dst = workFrame->commandData + workFrame->commandUsed; *dst = clientNum; Com_Memcpy( dst+1, s, len ); workFrame->commandUsed += len + 1; } break; case svc_gamestate: if (newHandle) { FS_FCloseFile( newHandle ); newHandle = 0; } if (levelCount) { Com_sprintf( newName, sizeof( newName ), "%s.%d.mme", newBaseName, levelCount ); } else { Com_sprintf( newName, sizeof( newName ), "%s.mme", newBaseName ); } fullTime = -1; clientNum = -1; oldTime = -1; Com_Memset( convert, 0, sizeof( *convert )); convert->frames[0].string.used = 1; levelCount++; newHandle = FS_FOpenFileWrite( newName ); if (!newHandle) { Com_Printf("Failed to open %s for target conversion target.\n", newName); goto conversionerror; return; } else { FS_Write ( demoHeader, strlen( demoHeader ), newHandle ); } Com_sprintf( newName, sizeof( newName ), "%s.txt", newBaseName ); workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ]; msgSequence = MSG_ReadLong( &oldMsg ); while( 1 ) { cmd = MSG_ReadByte( &oldMsg ); if (cmd == svc_EOF) break; if ( cmd == svc_configstring) { int num; const char *s; num = MSG_ReadShort( &oldMsg ); s = MSG_ReadBigString( &oldMsg ); demoFrameAddString( &workFrame->string, num, s ); } else if ( cmd == svc_baseline ) { int num = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); if ( num < 0 || num >= MAX_GENTITIES ) { Com_Printf( "Baseline number out of range: %i.\n", num ); goto conversionerror; } MSG_ReadDeltaEntity( &oldMsg, &demoNullEntityState, &convert->entityBaselines[num], num ); } else { Com_Printf( "Unknown block while converting demo gamestate.\n" ); goto conversionerror; } } clientNum = MSG_ReadLong( &oldMsg ); /* Skip the checksum feed */ MSG_ReadLong( &oldMsg ); break; case svc_snapshot: nextTime = MSG_ReadLong( &oldMsg ); /* Delta number, not needed */ newSnap = &convert->snapshots[convert->messageNum & PACKET_MASK]; Com_Memset (newSnap, 0, sizeof(*newSnap)); newSnap->deltaNum = MSG_ReadByte( &oldMsg ); newSnap->messageNum = convert->messageNum; if (!newSnap->deltaNum) { newSnap->deltaNum = -1; newSnap->valid = qtrue; // uncompressed frame oldSnap = NULL; } else { newSnap->deltaNum = newSnap->messageNum - newSnap->deltaNum; oldSnap = &convert->snapshots[newSnap->deltaNum & PACKET_MASK]; if (!oldSnap->valid) { Com_Printf( "Delta snapshot without base.\n" ); goto conversionerror; } else if (oldSnap->messageNum != newSnap->deltaNum) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); } else if ( parseEntitiesNum - oldSnap->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { Com_Printf ("Delta parseEntitiesNum too old.\n"); } else { newSnap->valid = qtrue; // valid delta parse } } /* Snapflags, not needed */ newSnap->snapFlags = MSG_ReadByte( &oldMsg ); // read areamask workFrame->areaUsed = MSG_ReadByte( &oldMsg ); MSG_ReadData( &oldMsg, workFrame->areamask, workFrame->areaUsed ); if (clientNum <0 || clientNum >= MAX_CLIENTS) { Com_Printf("Got snapshot with invalid client.\n"); goto conversionerror; } MSG_ReadDeltaPlayerstate( &oldMsg, oldSnap ? &oldSnap->ps : &demoNullPlayerState, &newSnap->ps ); /* Read the individual entities */ newSnap->parseEntitiesNum = parseEntitiesNum; newSnap->numEntities = 0; Com_Memset( workFrame->entityData, 0, sizeof( workFrame->entityData )); /* The beast that is entity parsing */ { int newnum; entityState_t *oldstate, *newstate; int oldindex = 0; int oldnum; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); while ( 1 ) { // read the entity index number if (oldSnap && oldindex < oldSnap->numEntities) { oldstate = &convert->parseEntities[(oldSnap->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } else { oldstate = 0; oldnum = 99999; } newstate = &convert->parseEntities[parseEntitiesNum]; if ( !oldstate && (newnum == (MAX_GENTITIES-1))) { break; } else if ( oldnum < newnum ) { *newstate = *oldstate; oldindex++; } else if (oldnum == newnum) { oldindex++; MSG_ReadDeltaEntity( &oldMsg, oldstate, newstate, newnum ); if ( newstate->number != MAX_GENTITIES-1) workFrame->entityData[ newstate->number ] = 1; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); } else if (oldnum > newnum) { MSG_ReadDeltaEntity( &oldMsg, &convert->entityBaselines[newnum], newstate , newnum ); if ( newstate->number != MAX_GENTITIES-1) workFrame->entityData[ newstate->number ] = 1; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); } if (newstate->number == MAX_GENTITIES-1) continue; parseEntitiesNum++; parseEntitiesNum &= (MAX_PARSE_ENTITIES-1); newSnap->numEntities++; }} /* Stop processing this further since it's an invalid snap due to lack of delta data */ if (!newSnap->valid) break; /* Skipped snapshots will be set invalid in the circular buffer */ if ( newSnap->messageNum - convert->lastMessageNum >= PACKET_BACKUP ) { convert->lastMessageNum = newSnap->messageNum - ( PACKET_BACKUP - 1 ); } for ( ; convert->lastMessageNum < newSnap->messageNum ; convert->lastMessageNum++ ) { convert->snapshots[convert->lastMessageNum & PACKET_MASK].valid = qfalse; } convert->lastMessageNum = newSnap->messageNum + 1; /* compress the frame into the new format */ if (nextTime > oldTime) { demoFrame_t *cleanFrame; int writeIndex; for (temp = 0;temp<newSnap->numEntities;temp++) { int p = (newSnap->parseEntitiesNum+temp) & (MAX_PARSE_ENTITIES-1); entityState_t *newState = &convert->parseEntities[p]; workFrame->entities[newState->number] = *newState; } workFrame->clientData[clientNum] = 1; workFrame->clients[clientNum] = newSnap->ps; workFrame->serverTime = nextTime; /* Which frame from the cache to save */ writeIndex = convert->frameIndex - (DEMOCONVERTFRAMES/2); if (writeIndex >= 0) { const demoFrame_t *newFrame; msg_t writeMsg; // init the message MSG_Init( &writeMsg, demoBuffer, sizeof (demoBuffer)); MSG_Clear( &writeMsg ); MSG_Bitstream( &writeMsg ); newFrame = &convert->frames[ writeIndex % DEMOCONVERTFRAMES]; if ( smoothen ) demoFrameInterpolate( convert->frames, DEMOCONVERTFRAMES, writeIndex ); if ( nextTime > fullTime || writeIndex <= 0 ) { /* Plan the next time for a full write */ fullTime = nextTime + 2000; demoFramePack( &writeMsg, newFrame, 0 ); } else { const demoFrame_t *oldFrame = &convert->frames[ ( writeIndex -1 ) % DEMOCONVERTFRAMES]; demoFramePack( &writeMsg, newFrame, oldFrame ); } /* Write away the new data in the msg queue */ temp = LittleLong( writeMsg.cursize ); FS_Write (&temp, 4, newHandle ); FS_Write ( writeMsg.data , writeMsg.cursize, newHandle ); } /* Clean up the upcoming frame for all new changes */ convert->frameIndex++; cleanFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES]; cleanFrame->serverTime = 0; for (temp = 0;temp<MAX_GENTITIES;temp++) cleanFrame->entities[temp].number = MAX_GENTITIES-1; Com_Memset( cleanFrame->clientData, 0, sizeof ( cleanFrame->clientData )); Com_Memcpy( cleanFrame->string.data, workFrame->string.data, workFrame->string.used ); Com_Memcpy( cleanFrame->string.offsets, workFrame->string.offsets, sizeof( workFrame->string.offsets )); cleanFrame->string.used = workFrame->string.used; cleanFrame->commandUsed = 0; /* keep track of this last frame's time */ oldTime = nextTime; } break; case svc_download: // read block number temp = MSG_ReadShort ( &oldMsg ); if (!temp) //0 block, read file size MSG_ReadLong( &oldMsg ); // read block size temp = MSG_ReadShort ( &oldMsg ); // read the data block for ( ;temp>0;temp--) MSG_ReadByte( &oldMsg ); break; } } } conversionerror: FS_FCloseFile( oldHandle ); FS_FCloseFile( newHandle ); Z_Free( convert ); return; }
/* ============ Cmd_Alias_f ============ */ void Cmd_Alias_f(void) { cmd_alias_t *alias; const char *name; // Get args if (Cmd_Argc() < 2) { Com_Printf("alias <name> : show an alias\n"); Com_Printf("alias <name> <exec> : create an alias\n"); return; } name = Cmd_Argv(1); // Find existing alias for (alias = cmd_aliases; alias; alias = alias->next) { if (!Q_stricmp(name, alias->name)) break; } // Modify/create an alias if (Cmd_Argc() > 2) { cmd_function_t *cmd; // Crude protection from infinite loops if (!Q_stricmp(Cmd_Argv(2), name)) { Com_Printf("Can't make an alias to itself\n"); return; } // Don't allow overriding builtin commands cmd = Cmd_FindCommand( name ); if (cmd && cmd->function != Cmd_RunAlias_f) { Com_Printf("Can't override a builtin function with an alias\n"); return; } // Create/update an alias if (!alias) { alias = (cmd_alias_t*)S_Malloc(sizeof(cmd_alias_t)); alias->name = CopyString(name); alias->exec = CopyString(Cmd_ArgsFrom(2)); alias->next = cmd_aliases; cmd_aliases = alias; Cmd_AddCommand(name, Cmd_RunAlias_f, NULL); } else { // Reallocate the exec string Z_Free(alias->exec); alias->exec = CopyString(Cmd_ArgsFrom(2)); Cmd_AddCommand(name, Cmd_RunAlias_f, NULL); } } // Show the alias if (!alias) Com_Printf("Alias %s does not exist\n", name); else if (Cmd_Argc() == 2) Com_Printf("%s ==> %s\n", alias->name, alias->exec); // update autogen.cfg cvar_modifiedFlags |= CVAR_ARCHIVE; }
/* ============ Cmd_ArgsFromBuffer The interpreted versions use this because they can't have pointers returned to them ============ */ void Cmd_ArgsFromBuffer( int arg, char *buffer, int bufferLength ) { Q_strncpyz( buffer, Cmd_ArgsFrom( arg ), bufferLength ); }
/* ==================== 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; }
/* ============ Cmd_ArgsBuffer The interpreted versions use this because they can't have pointers returned to them ============ */ void Cmd_ArgsBuffer( char *buffer, int bufferLength ) { Q_strncpyz( buffer, Cmd_ArgsFrom( 1 ), bufferLength ); }
/* ============ Cmd_Args Returns a single string containing argv(1) to argv(argc()-1) ============ */ char *Cmd_Args( void ) { return Cmd_ArgsFrom( 1 ); }
/* ===================== CL_ConfigstringModified ===================== */ void CL_ConfigstringModified( void ) { char *old, *s; int i, index; char *dup; gameState_t oldGs; int len; index = atoi( Cmd_Argv(1) ); if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { Com_Error( ERR_DROP, "CL_ConfigstringModified: bad index %i", index ); } // get everything after "cs <num>" s = Cmd_ArgsFrom(2); old = cl.gameState.stringData + cl.gameState.stringOffsets[ index ]; if ( !strcmp( old, s ) ) { return; // unchanged } // build the new gameState_t oldGs = cl.gameState; Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) ); // leave the first 0 for uninitialized strings cl.gameState.dataCount = 1; for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( i == index ) { dup = s; } else { dup = oldGs.stringData + oldGs.stringOffsets[ i ]; } if ( !dup[0] ) { continue; // leave with the default empty string } len = strlen( dup ); if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) { Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" ); } // append it to the gameState string buffer cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount; Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, dup, len + 1 ); cl.gameState.dataCount += len + 1; } if (cl_autolodscale && cl_autolodscale->integer) { if (index >= CS_PLAYERS && index < CS_G2BONES) { //this means that a client was updated in some way. Go through and count the clients. int clientCount = 0; i = CS_PLAYERS; while (i < CS_G2BONES) { s = cl.gameState.stringData + cl.gameState.stringOffsets[ i ]; if (s && s[0]) { clientCount++; } i++; } gCLTotalClientNum = clientCount; #ifdef _DEBUG Com_DPrintf("%i clients\n", gCLTotalClientNum); #endif CL_DoAutoLODScale(); } } if ( index == CS_SYSTEMINFO ) { // parse serverId and other cvars CL_SystemInfoChanged(); } }
const char* Cmd_Args() { return Cmd_ArgsFrom(1); }