]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/framework/CmdSystem.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / framework / CmdSystem.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 /*
33 ===============================================================================
34
35         idCmdSystemLocal
36
37 ===============================================================================
38 */
39
40 typedef struct commandDef_s {
41         struct commandDef_s *   next;
42         char *                                  name;
43         cmdFunction_t                   function;
44         argCompletion_t                 argCompletion;
45         int                                             flags;
46         char *                                  description;
47 } commandDef_t;
48
49
50 class idCmdSystemLocal : public idCmdSystem {
51 public:
52         virtual void                    Init( void );
53         virtual void                    Shutdown( void );
54
55         virtual void                    AddCommand( const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion = NULL );
56         virtual void                    RemoveCommand( const char *cmdName );
57         virtual void                    RemoveFlaggedCommands( int flags );
58
59         virtual void                    CommandCompletion( void(*callback)( const char *s ) );
60         virtual void                    ArgCompletion( const char *cmdString, void(*callback)( const char *s ) );
61
62         virtual void                    BufferCommandText( cmdExecution_t exec, const char *text );
63         virtual void                    ExecuteCommandBuffer( void );
64
65         virtual void                    ArgCompletion_FolderExtension( const idCmdArgs &args, void(*callback)( const char *s ), const char *folder, bool stripFolder, ... );
66         virtual void                    ArgCompletion_DeclName( const idCmdArgs &args, void(*callback)( const char *s ), int type );
67
68         virtual void                    BufferCommandArgs( cmdExecution_t exec, const idCmdArgs &args );
69
70         virtual void                    SetupReloadEngine( const idCmdArgs &args );
71         virtual bool                    PostReloadEngine( void );
72
73         void                                    SetWait( int numFrames ) { wait = numFrames; }
74         commandDef_t *                  GetCommands( void ) const { return commands; }
75
76 private:
77         static const int                MAX_CMD_BUFFER = 0x10000;
78
79         commandDef_t *                  commands;
80
81         int                                             wait;
82         int                                             textLength;
83         byte                                    textBuf[MAX_CMD_BUFFER];
84
85         idStr                                   completionString;
86         idStrList                               completionParms;
87
88         // piggybacks on the text buffer, avoids tokenize again and screwing it up
89         idList<idCmdArgs>               tokenizedCmds;
90
91         // a command stored to be executed after a reloadEngine and all associated commands have been processed
92         idCmdArgs                               postReload;
93
94 private:        
95         void                                    ExecuteTokenizedString( const idCmdArgs &args );
96         void                                    ExecuteCommandText( const char *text );
97         void                                    InsertCommandText( const char *text );
98         void                                    AppendCommandText( const char *text );
99
100         static void                             ListByFlags( const idCmdArgs &args, cmdFlags_t flags );
101         static void                             List_f( const idCmdArgs &args );
102         static void                             SystemList_f( const idCmdArgs &args );
103         static void                             RendererList_f( const idCmdArgs &args );
104         static void                             SoundList_f( const idCmdArgs &args );
105         static void                             GameList_f( const idCmdArgs &args );
106         static void                             ToolList_f( const idCmdArgs &args );
107         static void                             Exec_f( const idCmdArgs &args );
108         static void                             Vstr_f( const idCmdArgs &args );
109         static void                             Echo_f( const idCmdArgs &args );
110         static void                             Parse_f( const idCmdArgs &args );
111         static void                             Wait_f( const idCmdArgs &args );
112         static void                             PrintMemInfo_f( const idCmdArgs &args );
113 };
114
115 idCmdSystemLocal                        cmdSystemLocal;
116 idCmdSystem *                           cmdSystem = &cmdSystemLocal;
117
118
119 /*
120 ============
121 idCmdSystemLocal::ListByFlags
122 ============
123 */
124 // NOTE: the const wonkyness is required to make msvc happy
125 template<>
126 ID_INLINE int idListSortCompare( const commandDef_t * const *a, const commandDef_t * const *b ) {
127         return idStr::Icmp( (*a)->name, (*b)->name );
128 }
129
130 void idCmdSystemLocal::ListByFlags( const idCmdArgs &args, cmdFlags_t flags ) {
131         int i;
132         idStr match;
133         const commandDef_t *cmd;
134         idList<const commandDef_t *> cmdList;
135
136         if ( args.Argc() > 1 ) {
137                 match = args.Args( 1, -1 );
138                 match.Replace( " ", "" );
139         } else {
140                 match = "";
141         }
142
143         for ( cmd = cmdSystemLocal.GetCommands(); cmd; cmd = cmd->next ) {
144                 if ( !( cmd->flags & flags ) ) {
145                         continue;
146                 }
147                 if ( match.Length() && idStr( cmd->name ).Filter( match, false ) == 0 ) {
148                         continue;
149                 }
150
151                 cmdList.Append( cmd );
152         }
153
154         cmdList.Sort();
155
156         for ( i = 0; i < cmdList.Num(); i++ ) {
157                 cmd = cmdList[i];
158
159                 common->Printf( "  %-21s %s\n", cmd->name, cmd->description );
160         }
161
162         common->Printf( "%i commands\n", cmdList.Num() );
163 }
164
165 /*
166 ============
167 idCmdSystemLocal::List_f
168 ============
169 */
170 void idCmdSystemLocal::List_f( const idCmdArgs &args ) {
171         idCmdSystemLocal::ListByFlags( args, CMD_FL_ALL );
172 }
173
174 /*
175 ============
176 idCmdSystemLocal::SystemList_f
177 ============
178 */
179 void idCmdSystemLocal::SystemList_f( const idCmdArgs &args ) {
180         idCmdSystemLocal::ListByFlags( args, CMD_FL_SYSTEM );
181 }
182
183 /*
184 ============
185 idCmdSystemLocal::RendererList_f
186 ============
187 */
188 void idCmdSystemLocal::RendererList_f( const idCmdArgs &args ) {
189         idCmdSystemLocal::ListByFlags( args, CMD_FL_RENDERER );
190 }
191
192 /*
193 ============
194 idCmdSystemLocal::SoundList_f
195 ============
196 */
197 void idCmdSystemLocal::SoundList_f( const idCmdArgs &args ) {
198         idCmdSystemLocal::ListByFlags( args, CMD_FL_SOUND );
199 }
200
201 /*
202 ============
203 idCmdSystemLocal::GameList_f
204 ============
205 */
206 void idCmdSystemLocal::GameList_f( const idCmdArgs &args ) {
207         idCmdSystemLocal::ListByFlags( args, CMD_FL_GAME );
208 }
209
210 /*
211 ============
212 idCmdSystemLocal::ToolList_f
213 ============
214 */
215 void idCmdSystemLocal::ToolList_f( const idCmdArgs &args ) {
216         idCmdSystemLocal::ListByFlags( args, CMD_FL_TOOL );
217 }
218
219 /*
220 ===============
221 idCmdSystemLocal::Exec_f
222 ===============
223 */
224 void idCmdSystemLocal::Exec_f( const idCmdArgs &args ) {
225         char *  f;
226         int             len;
227         idStr   filename;
228
229         if ( args.Argc () != 2 ) {
230                 common->Printf( "exec <filename> : execute a script file\n" );
231                 return;
232         }
233
234         filename = args.Argv(1);
235         filename.DefaultFileExtension( ".cfg" );
236         len = fileSystem->ReadFile( filename, reinterpret_cast<void **>(&f), NULL );
237         if ( !f ) {
238                 common->Printf( "couldn't exec %s\n", args.Argv(1) );
239                 return;
240         }
241         common->Printf( "execing %s\n", args.Argv(1) );
242         
243         cmdSystemLocal.BufferCommandText( CMD_EXEC_INSERT, f );
244
245         fileSystem->FreeFile( f );
246 }
247
248 /*
249 ===============
250 idCmdSystemLocal::Vstr_f
251
252 Inserts the current value of a cvar as command text
253 ===============
254 */
255 void idCmdSystemLocal::Vstr_f( const idCmdArgs &args ) {
256         const char *v;
257
258         if ( args.Argc () != 2 ) {
259                 common->Printf( "vstr <variablename> : execute a variable command\n" );
260                 return;
261         }
262
263         v = cvarSystem->GetCVarString( args.Argv( 1 ) );
264
265         cmdSystemLocal.BufferCommandText( CMD_EXEC_APPEND, va( "%s\n", v ) );
266 }
267
268 /*
269 ===============
270 idCmdSystemLocal::Echo_f
271
272 Just prints the rest of the line to the console
273 ===============
274 */
275 void idCmdSystemLocal::Echo_f( const idCmdArgs &args ) {
276         int             i;
277         
278         for ( i = 1; i < args.Argc(); i++ ) {
279                 common->Printf( "%s ", args.Argv( i ) );
280         }
281         common->Printf( "\n" );
282 }
283
284 /*
285 ============
286 idCmdSystemLocal::Wait_f
287
288 Causes execution of the remainder of the command buffer to be delayed until next frame.
289 ============
290 */
291 void idCmdSystemLocal::Wait_f( const idCmdArgs &args ) {
292         if ( args.Argc() == 2 ) {
293                 cmdSystemLocal.SetWait( atoi( args.Argv( 1 ) ) );
294         } else {
295                 cmdSystemLocal.SetWait( 1 );
296         }
297 }
298
299 /*
300 ============
301 idCmdSystemLocal::Parse_f
302
303 This just prints out how the rest of the line was parsed, as a debugging tool.
304 ============
305 */
306 void idCmdSystemLocal::Parse_f( const idCmdArgs &args ) {
307         int             i;
308
309         for ( i = 0; i < args.Argc(); i++ ) {
310                 common->Printf( "%i: %s\n", i, args.Argv(i) );
311         }
312 }
313
314 /*
315 ============
316 idCmdSystemLocal::Init
317 ============
318 */
319 void idCmdSystemLocal::Init( void ) {
320
321         AddCommand( "listCmds", List_f, CMD_FL_SYSTEM, "lists commands" );
322         AddCommand( "listSystemCmds", SystemList_f, CMD_FL_SYSTEM, "lists system commands" );
323         AddCommand( "listRendererCmds", RendererList_f, CMD_FL_SYSTEM, "lists renderer commands" );
324         AddCommand( "listSoundCmds", SoundList_f, CMD_FL_SYSTEM, "lists sound commands" );
325         AddCommand( "listGameCmds", GameList_f, CMD_FL_SYSTEM, "lists game commands" );
326         AddCommand( "listToolCmds", ToolList_f, CMD_FL_SYSTEM, "lists tool commands" );
327         AddCommand( "exec", Exec_f, CMD_FL_SYSTEM, "executes a config file", ArgCompletion_ConfigName );
328         AddCommand( "vstr", Vstr_f, CMD_FL_SYSTEM, "inserts the current value of a cvar as command text" );
329         AddCommand( "echo", Echo_f, CMD_FL_SYSTEM, "prints text" );
330         AddCommand( "parse", Parse_f, CMD_FL_SYSTEM, "prints tokenized string" );
331         AddCommand( "wait", Wait_f, CMD_FL_SYSTEM, "delays remaining buffered commands one or more frames" );
332
333         completionString = "*";
334
335         textLength = 0;
336 }
337
338 /*
339 ============
340 idCmdSystemLocal::Shutdown
341 ============
342 */
343 void idCmdSystemLocal::Shutdown( void ) {
344         commandDef_t *cmd;
345
346         for ( cmd = commands; cmd; cmd = commands ) {
347                 commands = commands->next;
348                 Mem_Free( cmd->name );
349                 Mem_Free( cmd->description );
350                 delete cmd;
351         }
352
353         completionString.Clear();
354         completionParms.Clear();
355         tokenizedCmds.Clear();
356         postReload.Clear();
357 }
358
359 /*
360 ============
361 idCmdSystemLocal::AddCommand
362 ============
363 */
364 void idCmdSystemLocal::AddCommand( const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion ) {
365         commandDef_t *cmd;
366         
367         // fail if the command already exists
368         for ( cmd = commands; cmd; cmd = cmd->next ) {
369                 if ( idStr::Cmp( cmdName, cmd->name ) == 0 ) {
370                         if ( function != cmd->function ) {
371                                 common->Printf( "idCmdSystemLocal::AddCommand: %s already defined\n", cmdName );
372                         }
373                         return;
374                 }
375         }
376
377         cmd = new commandDef_t;
378         cmd->name = Mem_CopyString( cmdName );
379         cmd->function = function;
380         cmd->argCompletion = argCompletion;
381         cmd->flags = flags;
382         cmd->description = Mem_CopyString( description );
383         cmd->next = commands;
384         commands = cmd;
385 }
386
387 /*
388 ============
389 idCmdSystemLocal::RemoveCommand
390 ============
391 */
392 void idCmdSystemLocal::RemoveCommand( const char *cmdName ) {
393         commandDef_t *cmd, **last;
394
395         for ( last = &commands, cmd = *last; cmd; cmd = *last ) {
396                 if ( idStr::Cmp( cmdName, cmd->name ) == 0 ) {
397                         *last = cmd->next;
398                         Mem_Free( cmd->name );
399                         Mem_Free( cmd->description );
400                         delete cmd;
401                         return;
402                 }
403                 last = &cmd->next;
404         }
405 }
406
407 /*
408 ============
409 idCmdSystemLocal::RemoveFlaggedCommands
410 ============
411 */
412 void idCmdSystemLocal::RemoveFlaggedCommands( int flags ) {
413         commandDef_t *cmd, **last;
414
415         for ( last = &commands, cmd = *last; cmd; cmd = *last ) {
416                 if ( cmd->flags & flags ) {
417                         *last = cmd->next;
418                         Mem_Free( cmd->name );
419                         Mem_Free( cmd->description );
420                         delete cmd;
421                         continue;
422                 }
423                 last = &cmd->next;
424         }
425 }
426
427 /*
428 ============
429 idCmdSystemLocal::CommandCompletion
430 ============
431 */
432 void idCmdSystemLocal::CommandCompletion( void(*callback)( const char *s ) ) {
433         commandDef_t *cmd;
434         
435         for ( cmd = commands; cmd; cmd = cmd->next ) {
436                 callback( cmd->name );
437         }
438 }
439
440 /*
441 ============
442 idCmdSystemLocal::ArgCompletion
443 ============
444 */
445 void idCmdSystemLocal::ArgCompletion( const char *cmdString, void(*callback)( const char *s ) ) {
446         commandDef_t *cmd;
447         idCmdArgs args;
448
449         args.TokenizeString( cmdString, false );
450
451         for ( cmd = commands; cmd; cmd = cmd->next ) {
452                 if ( !cmd->argCompletion ) {
453                         continue;
454                 }
455                 if ( idStr::Icmp( args.Argv( 0 ), cmd->name ) == 0 ) {
456                         cmd->argCompletion( args, callback );
457                         break;
458                 }
459         }
460 }
461
462 /*
463 ============
464 idCmdSystemLocal::ExecuteTokenizedString
465 ============
466 */
467 void idCmdSystemLocal::ExecuteTokenizedString( const idCmdArgs &args ) {        
468         commandDef_t *cmd, **prev;
469         
470         // execute the command line
471         if ( !args.Argc() ) {
472                 return;         // no tokens
473         }
474
475         // check registered command functions   
476         for ( prev = &commands; *prev; prev = &cmd->next ) {
477                 cmd = *prev;
478                 if ( idStr::Icmp( args.Argv( 0 ), cmd->name ) == 0 ) {
479                         // rearrange the links so that the command will be
480                         // near the head of the list next time it is used
481                         *prev = cmd->next;
482                         cmd->next = commands;
483                         commands = cmd;
484
485                         if ( ( cmd->flags & (CMD_FL_CHEAT|CMD_FL_TOOL) ) && session && session->IsMultiplayer() && !cvarSystem->GetCVarBool( "net_allowCheats" ) ) {
486                                 common->Printf( "Command '%s' not valid in multiplayer mode.\n", cmd->name );
487                                 return;
488                         }
489                         // perform the action
490                         if ( !cmd->function ) {
491                                 break;
492                         } else {
493                                 cmd->function( args );
494                         }
495                         return;
496                 }
497         }
498         
499         // check cvars
500         if ( cvarSystem->Command( args ) ) {
501                 return;
502         }
503
504         common->Printf( "Unknown command '%s'\n", args.Argv( 0 ) );
505 }
506
507 /*
508 ============
509 idCmdSystemLocal::ExecuteCommandText
510
511 Tokenizes, then executes.
512 ============
513 */
514 void idCmdSystemLocal::ExecuteCommandText( const char *text ) { 
515         ExecuteTokenizedString( idCmdArgs( text, false ) );
516 }
517
518 /*
519 ============
520 idCmdSystemLocal::InsertCommandText
521
522 Adds command text immediately after the current command
523 Adds a \n to the text
524 ============
525 */
526 void idCmdSystemLocal::InsertCommandText( const char *text ) {
527         int             len;
528         int             i;
529
530         len = strlen( text ) + 1;
531         if ( len + textLength > (int)sizeof( textBuf ) ) {
532                 common->Printf( "idCmdSystemLocal::InsertText: buffer overflow\n" );
533                 return;
534         }
535
536         // move the existing command text
537         for ( i = textLength - 1; i >= 0; i-- ) {
538                 textBuf[ i + len ] = textBuf[ i ];
539         }
540
541         // copy the new text in
542         memcpy( textBuf, text, len - 1 );
543
544         // add a \n
545         textBuf[ len - 1 ] = '\n';
546
547         textLength += len;
548 }
549
550 /*
551 ============
552 idCmdSystemLocal::AppendCommandText
553
554 Adds command text at the end of the buffer, does NOT add a final \n
555 ============
556 */
557 void idCmdSystemLocal::AppendCommandText( const char *text ) {
558         int l;
559         
560         l = strlen( text );
561
562         if ( textLength + l >= (int)sizeof( textBuf ) ) {
563                 common->Printf( "idCmdSystemLocal::AppendText: buffer overflow\n" );
564                 return;
565         }
566         memcpy( textBuf + textLength, text, l );
567         textLength += l;
568 }
569
570 /*
571 ============
572 idCmdSystemLocal::BufferCommandText
573 ============
574 */
575 void idCmdSystemLocal::BufferCommandText( cmdExecution_t exec, const char *text ) {
576         switch( exec ) {
577                 case CMD_EXEC_NOW: {
578                         ExecuteCommandText( text );
579                         break;
580                 }
581                 case CMD_EXEC_INSERT: {
582                         InsertCommandText( text );
583                         break;
584                 }
585                 case CMD_EXEC_APPEND: {
586                         AppendCommandText( text );
587                         break;
588                 }
589                 default: {
590                         common->FatalError( "idCmdSystemLocal::BufferCommandText: bad exec type" );
591                 }
592         }
593 }
594
595 /*
596 ============
597 idCmdSystemLocal::BufferCommandArgs
598 ============
599 */
600 void idCmdSystemLocal::BufferCommandArgs( cmdExecution_t exec, const idCmdArgs &args ) {
601         switch ( exec ) {
602                 case CMD_EXEC_NOW: {
603                         ExecuteTokenizedString( args );
604                         break;
605                 }
606                 case CMD_EXEC_APPEND: {
607                         AppendCommandText( "_execTokenized\n" );
608                         tokenizedCmds.Append( args );
609                         break;
610                 }
611                 default: {
612                         common->FatalError( "idCmdSystemLocal::BufferCommandArgs: bad exec type" );
613                 }
614         }
615 }
616
617 /*
618 ============
619 idCmdSystemLocal::ExecuteCommandBuffer
620 ============
621 */
622 void idCmdSystemLocal::ExecuteCommandBuffer( void ) {
623         int                     i;
624         char *          text;
625         int                     quotes;
626         idCmdArgs       args;
627
628         while( textLength ) {
629
630                 if ( wait )     {
631                         // skip out while text still remains in buffer, leaving it for next frame
632                         wait--;
633                         break;
634                 }
635
636                 // find a \n or ; line break
637                 text = (char *)textBuf;
638
639                 quotes = 0;
640                 for ( i = 0; i < textLength; i++ ) {
641                         if ( text[i] == '"' ) {
642                                 quotes++;
643                         }
644                         if ( !( quotes & 1 ) &&  text[i] == ';' ) {
645                                 break;  // don't break if inside a quoted string
646                         }
647                         if ( text[i] == '\n' || text[i] == '\r' ) {
648                                 break;
649                         }
650                 }
651                         
652                 text[i] = 0;
653
654                 if ( !idStr::Cmp( text, "_execTokenized" ) ) {
655                         args = tokenizedCmds[ 0 ];
656                         tokenizedCmds.RemoveIndex( 0 );
657                 } else {
658                         args.TokenizeString( text, false );
659                 }
660
661                 // delete the text from the command buffer and move remaining commands down
662                 // this is necessary because commands (exec) can insert data at the
663                 // beginning of the text buffer
664
665                 if ( i == textLength ) {
666                         textLength = 0;
667                 } else {
668                         i++;
669                         textLength -= i;
670                         memmove( text, text+i, textLength );
671                 }
672
673                 // execute the command line that we have already tokenized
674                 ExecuteTokenizedString( args );
675         }
676 }
677
678 /*
679 ============
680 idCmdSystemLocal::ArgCompletion_FolderExtension
681 ============
682 */
683 void idCmdSystemLocal::ArgCompletion_FolderExtension( const idCmdArgs &args, void(*callback)( const char *s ), const char *folder, bool stripFolder, ... ) {
684         int i;
685         idStr string;
686         const char *extension;
687         va_list argPtr;
688
689         string = args.Argv( 0 );
690         string += " ";
691         string += args.Argv( 1 );
692
693         if ( string.Icmp( completionString ) != 0 ) {
694                 idStr parm, path;
695                 idFileList *names;
696
697                 completionString = string;
698                 completionParms.Clear();
699
700                 parm = args.Argv( 1 );
701                 parm.ExtractFilePath( path );
702                 if ( stripFolder || path.Length() == 0 ) {
703                         path = folder + path;
704                 }
705                 path.StripTrailing( '/' );
706
707                 // list folders
708                 names = fileSystem->ListFiles( path, "/", true, true );
709                 for ( i = 0; i < names->GetNumFiles(); i++ ) {
710                         idStr name = names->GetFile( i );
711                         if ( stripFolder ) {
712                                 name.Strip( folder );
713                         } else {
714                                 name.Strip( "/" );
715                         }
716                         name = args.Argv( 0 ) + ( " " + name ) + "/";
717                         completionParms.Append( name );
718                 }
719                 fileSystem->FreeFileList( names );
720
721                 // list files
722                 va_start( argPtr, stripFolder );
723                 for ( extension = va_arg( argPtr, const char * ); extension; extension = va_arg( argPtr, const char * ) ) {
724                         names = fileSystem->ListFiles( path, extension, true, true );
725                         for ( i = 0; i < names->GetNumFiles(); i++ ) {
726                                 idStr name = names->GetFile( i );
727                                 if ( stripFolder ) {
728                                         name.Strip( folder );
729                                 } else {
730                                         name.Strip( "/" );
731                                 }
732                                 name = args.Argv( 0 ) + ( " " + name );
733                                 completionParms.Append( name );
734                         }
735                         fileSystem->FreeFileList( names );
736                 }
737                 va_end( argPtr );
738         }
739         for ( i = 0; i < completionParms.Num(); i++ ) {
740                 callback( completionParms[i] );
741         }
742 }
743
744 /*
745 ============
746 idCmdSystemLocal::ArgCompletion_DeclName
747 ============
748 */
749 void idCmdSystemLocal::ArgCompletion_DeclName( const idCmdArgs &args, void(*callback)( const char *s ), int type ) {
750         int i, num;
751
752         if ( declManager == NULL ) {
753                 return;
754         }
755         num = declManager->GetNumDecls( (declType_t)type );
756         for ( i = 0; i < num; i++ ) {
757                 callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( (declType_t)type, i , false )->GetName() );
758         }
759 }
760
761 /*
762 ============
763 idCmdSystemLocal::SetupReloadEngine
764 ============
765 */
766 void idCmdSystemLocal::SetupReloadEngine( const idCmdArgs &args ) {
767         BufferCommandText( CMD_EXEC_APPEND, "reloadEngine\n" );
768         postReload = args;
769 }
770
771 /*
772 ============
773 idCmdSystemLocal::PostReloadEngine
774 ============
775 */
776 bool idCmdSystemLocal::PostReloadEngine( void ) {
777         if ( !postReload.Argc() ) {
778                 return false;
779         }
780         BufferCommandArgs( CMD_EXEC_APPEND, postReload );
781         postReload.Clear();
782         return true;
783 }