History

the only constant is change.

Ge Wang committed 9 years ago

Commit 009ac191 parent b1e2669181 files · +0 −3911Browse files

Showing the changes to src/core/chuck_shell.cpp (1 of 181 files). Show all

Unified · Split

src/core/chuck_shell.cpp+2260−0
@@ -0,0 +1,2260 @@
1/*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
4
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.stanford.edu/
7 http://chuck.cs.princeton.edu/
8
9 This program 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 2 of the License, or
12 (at your option) any later version.
13
14 This program 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 this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23-----------------------------------------------------------------------------*/
24
25//-----------------------------------------------------------------------------
26// file: chuck_shell.cpp
27// desc: chuck shell implementation
28//
29// author: Spencer Salazar (spencer@ccrma.stanford.edu)
30// date: Autumn 2005
31//-----------------------------------------------------------------------------
32#include "chuck_shell.h"
33#include "chuck_otf.h"
34#include "chuck_globals.h"
35#include "chuck_errmsg.h"
36#include "util_network.h"
37#include "util_string.h"
38
39#include <stdio.h>
40#include <errno.h>
41#include <ctype.h>
42#ifndef __PLATFORM_WIN32__
43 #include <unistd.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <dirent.h>
47#endif
48
49using namespace std;
50
51// REFACTOR-2017: TODO Ge: where should this live? not in chuck_main if it's in core!
52// global shell pointer (lives in chuck_main)
53Chuck_Shell * g_shell;
54
55//-----------------------------------------------------------------------------
56// name: tokenize_string
57// desc: divides a string into space separated tokens, respecting single and
58// double quotes
59//-----------------------------------------------------------------------------
60void tokenize_string( string str, vector< string > & tokens)
61{
62 t_CKINT space = 1;
63 t_CKINT end_space = 0;
64 t_CKINT squote = 0;
65 t_CKINT dquote = 0;
66 t_CKINT i = 0, j = 0, len = str.size();
67
68 for( i = 0; i < len; i++ )
69 {
70 if( isspace( str[i] ) && space )
71 {
72 j++;
73 continue;
74 }
75
76 if( isspace( str[i] ) && end_space )
77 {
78 tokens.push_back( string( str, j, i - j ) );
79 j = i + 1;
80 space = 1;
81 end_space = 0;
82 continue;
83 }
84
85 if( str[i] == '\'' )
86 {
87 if( dquote )
88 continue;
89 if( !squote )
90 {
91 str.erase( i, 1 );
92 len--;
93 i--;
94 space = 0;
95 end_space = 0;
96 squote = 1;
97 continue;
98 }
99
100 else if( str[i - 1] == '\\' )
101 {
102 str.erase( i - 1, 1 );
103 len--;
104 i--;
105 continue;
106 }
107
108 else
109 {
110 str.erase( i, 1 );
111 len--;
112 i--;
113 squote = 0;
114 end_space = 1;
115 space = 0;
116 continue;
117 }
118 }
119
120 if( str[i] == '"' ) //"
121 {
122 if( squote )
123 continue;
124 if( !dquote )
125 {
126 str.erase( i, 1 );
127 i--;
128 len--;
129 space = 0;
130 end_space = 0;
131 dquote = 1;
132 continue;
133 }
134
135 else if( str[i - 1] == '\\' )
136 {
137 str.erase( i - 1, 1 );
138 len--;
139 i--;
140 continue;
141 }
142
143 else
144 {
145 str.erase( i, 1 );
146 i--;
147 len--;
148 dquote = 0;
149 end_space = 1;
150 space = 0;
151 continue;
152 }
153 }
154
155 if( !squote && !dquote )
156 {
157 end_space = 1;
158 space = 0;
159 }
160 }
161
162 if( i > j && end_space )
163 {
164 tokens.push_back( string( str, j, i - j ) );
165 }
166}
167
168//-----------------------------------------------------------------------------
169// name: win32_tmpnam()
170// desc: replacement for broken tmpnam() on Windows Vista + 7
171// file_path should be at least MAX_PATH characters.
172//-----------------------------------------------------------------------------
173#ifdef __PLATFORM_WIN32__
174
175#include <windows.h>
176
177int win32_tmpnam(char *file_path)
178{
179 char tmp_path[MAX_PATH];
180
181 if(GetTempPath(256, tmp_path) == 0)
182 return 0;
183
184 if(GetTempFileName(tmp_path, "cksh", 0, file_path) == 0)
185 return 0;
186
187 return 1;
188}
189
190#endif
191
192
193//-----------------------------------------------------------------------------
194// name: shell_cb
195// desc: thread routine
196//-----------------------------------------------------------------------------
197void * shell_cb( void * p )
198{
199 Chuck_Shell * shell;
200 // log
201 EM_log( CK_LOG_INFO, "starting thread routine for shell..." );
202
203 // assuming this is absolutely necessary, an assert may be better
204 assert( p != NULL );
205
206 shell = ( Chuck_Shell * ) p;
207
208 //atexit( wait_for_shell );
209
210 // run the shell
211 shell->run();
212
213 // delete and set to NULL
214 SAFE_DELETE( g_shell );
215 // perhaps let shell destructor clean up mode and ui?
216
217 EM_log( CK_LOG_INFO, "exiting thread routine for shell..." );
218
219 return NULL;
220}
221
222
223
224
225//-----------------------------------------------------------------------------
226// name: Chuck_Shell()
227// desc: ...
228//-----------------------------------------------------------------------------
229Chuck_Shell::Chuck_Shell()
230{
231 ui = NULL;
232 process_vm = NULL;
233 current_vm = NULL;
234 initialized = FALSE;
235 stop = FALSE;
236 code_entry_active = FALSE;
237}
238
239//-----------------------------------------------------------------------------
240// name: ~Chuck_Shell()
241// desc: ...
242//-----------------------------------------------------------------------------
243Chuck_Shell::~Chuck_Shell()
244{
245 vector<string>::size_type i, len = allocated_commands.size();
246
247 //iterate through commands, delete the associated heap data
248 for( i = 0; i != len; i++ )
249 SAFE_DELETE( allocated_commands[i] );
250
251 // delete ui
252 SAFE_DELETE( ui );
253
254 // flag
255 initialized = FALSE;
256}
257
258//-----------------------------------------------------------------------------
259// name: init()
260// desc: ...
261//-----------------------------------------------------------------------------
262t_CKBOOL Chuck_Shell::init( Chuck_VM * vm, Chuck_Shell_UI * ui )
263{
264 // log
265 EM_log( CK_LOG_SYSTEM, "initializing chuck shell..." );
266
267 // check
268 if( initialized == TRUE )
269 {
270 EM_log( CK_LOG_WARNING, "chuck shell already initialized" );
271 return TRUE;
272 }
273
274 // ui
275 if( ui == NULL )
276 {
277 CK_FPRINTF_STDERR( "[chuck](via shell): NULL ui passed to Chuck_Shell::init..." );
278 return FALSE;
279 }
280
281 this->ui = ui;
282
283 process_vm = vm;
284
285 Chuck_Shell_Network_VM * cspv = new Chuck_Shell_Network_VM();
286 if( !cspv->init( "localhost", 8888 ) )
287 {
288 CK_FPRINTF_STDERR( "[chuck](via shell): error initializing process VM..." );
289 SAFE_DELETE( cspv );
290 return FALSE;
291 }
292
293 current_vm = cspv;
294 vms.push_back( current_vm->copy() );
295
296 process_vm = vm;
297
298 code_entry_active = FALSE;
299 code = "";
300
301 // init default variables
302 variables["COMMAND_PROMPT"] = "chuck %> ";
303 variables["DEFAULT_CONTEXT"] = "shell_global";
304
305 // initialize prompt
306 prompt = variables["COMMAND_PROMPT"];
307
308 Command * temp;
309
310 // initialize the string -> Chuck_Shell_Command map
311 temp = new Command_VM();
312 temp->init( this );
313 commands["vm"] = temp;
314 allocated_commands.push_back( temp );
315
316 temp = new Command_VMList();
317 temp->init( this );
318 commands["vms"] = temp;
319 allocated_commands.push_back( temp );
320
321 temp = new Command_Add();
322 temp->init( this );
323 commands["+"] = temp;
324 commands["add"] = temp;
325 allocated_commands.push_back( temp );
326
327 temp = new Command_Remove();
328 temp->init( this );
329 commands["-"] = temp;
330 commands["remove"] = temp;
331 allocated_commands.push_back( temp );
332
333 temp = new Command_Status();
334 temp->init( this );
335 commands["status"] = temp;
336 commands["^"] = temp;
337 allocated_commands.push_back( temp );
338
339 temp = new Command_Removeall();
340 temp->init( this );
341 commands["removeall"] = temp;
342 allocated_commands.push_back( temp );
343
344 temp = new Command_Removelast();
345 temp->init( this );
346 commands["--"] = temp;
347 allocated_commands.push_back( temp );
348
349 temp = new Command_Replace();
350 temp->init( this );
351 commands["replace"] = temp;
352 commands["="] = temp;
353 allocated_commands.push_back( temp );
354
355 temp = new Command_Close();
356 temp->init( this );
357 commands["close"] = temp;
358 allocated_commands.push_back( temp );
359
360 temp = new Command_Kill();
361 temp->init( this );
362 commands["kill"] = temp;
363 allocated_commands.push_back( temp );
364
365 temp = new Command_Exit();
366 temp->init( this );
367 commands["exit"] = temp;
368 commands["quit"] = temp;
369 allocated_commands.push_back( temp );
370
371 temp = new Command_Ls();
372 temp->init( this );
373 commands["ls"] = temp;
374 allocated_commands.push_back( temp );
375
376 temp = new Command_Pwd();
377 temp->init( this );
378 commands["pwd"] = temp;
379 allocated_commands.push_back( temp );
380
381 temp = new Command_Cd();
382 temp->init( this );
383 commands["cd"] = temp;
384 allocated_commands.push_back( temp );
385
386 temp = new Command_Alias();
387 temp->init( this );
388 commands["alias"] = temp;
389 allocated_commands.push_back( temp );
390
391 temp = new Command_Unalias();
392 temp->init( this );
393 commands["unalias"] = temp;
394 allocated_commands.push_back( temp );
395
396 temp = new Command_Source();
397 temp->init( this );
398 commands["source"] = temp;
399 commands["."] = temp;
400 allocated_commands.push_back( temp );
401
402 temp = new Command_Code();
403 temp->init( this );
404 commands["code"] = temp;
405 allocated_commands.push_back( temp );
406
407 // flag
408 initialized = TRUE;
409
410 return TRUE;
411}
412
413//-----------------------------------------------------------------------------
414// name: run()
415// desc: ...
416//-----------------------------------------------------------------------------
417void Chuck_Shell::run()
418{
419 // log
420 EM_log( CK_LOG_SYSTEM, "running chuck shell..." );
421
422 // make sure
423 if(initialized == FALSE)
424 {
425 CK_FPRINTF_STDERR( "[chuck](via shell): shell not initialized...\n" );
426 return;
427 }
428
429 string command;
430 string result;
431
432 ui->next_result( "welcome to chuck shell!\n" );
433 // ui->next_result( "(type \"help\" for more information)\n" );
434
435 // loop
436 for( ; !stop; )
437 {
438 // get command
439 if( ui->next_command( prompt, command ) == TRUE )
440 {
441 // result.clear();
442 result = "";
443
444 //printf( "chuck_shell::run\n" );
445
446 // execute the command
447 execute( command, result );
448
449 // command.clear();
450 command = "";
451
452 // pass the result to the shell ui
453 ui->next_result( result );
454 }
455 else
456 // done
457 break;
458 }
459
460 // log
461 EM_log( CK_LOG_SYSTEM, "exiting chuck shell..." );
462}
463
464//-----------------------------------------------------------------------------
465// name: execute
466// desc: ...
467//-----------------------------------------------------------------------------
468t_CKBOOL Chuck_Shell::execute( string & in, string & out )
469{
470 if( !initialized )
471 {
472 return FALSE;
473 }
474
475 // vector of string tokens
476 vector< string > vec;
477
478 // clear the response
479 out = "";
480
481 // first find out if this is code to run
482 if( !code_entry_active && in[in.find_first_not_of( " \t\v\n" )] == '{' )
483 start_code();
484
485 if( code_entry_active )
486 {
487 continue_code( in );
488
489 if( code_entry_active == FALSE )
490 {
491 //strip opening and closing braces
492 string::size_type k = code.find( "{" );
493 string head = string( code, 0, k );
494 code = string( code, k + 1, code.size() - k - 1 );
495
496 k = code.rfind( "}" );
497 string tail = string( code, k + 1, code.size() - k - 1 );
498 code = string( code, 0, k );
499
500 do_code( code, out );
501
502 tokenize_string( tail, vec );
503
504 if( vec.size() > 0 )
505 {
506 string temp = "code save " + vec[0];
507 execute( temp, out );
508 }
509 }
510
511 return TRUE;
512 }
513
514 // divide the string into white space separated substrings
515 tokenize_string( in, vec );
516
517 // if no tokens
518 if( vec.size() == 0)
519 return TRUE;
520
521 // first check if the first token matches an alias
522 while( aliases.find( vec[0] ) != aliases.end() )
523 // use a while loop to handle nested aliases
524 {
525 vector< string > vec2;
526 tokenize_string( aliases[vec[0]], vec2 );
527 vec.erase( vec.begin() );
528 vec2.insert( vec2.end(), vec.begin(), vec.end() );
529 vec = vec2;
530 }
531
532 // locate the command
533 if( commands.find( vec[0] ) == commands.end() )
534 // command doesn't exist!
535 {
536 out += vec[0] + ": command not found\n";
537 return FALSE;
538 }
539
540 else
541 // execute the command
542 {
543 Command * command = commands[vec[0]];
544 vec.erase( vec.begin() );
545 if( command->execute( vec, out ) == 0 )
546 return TRUE;
547
548 else
549 return FALSE;
550 }
551
552 return TRUE;
553}
554
555//-----------------------------------------------------------------------------
556// name: start_code()
557// desc: ...
558//-----------------------------------------------------------------------------
559void Chuck_Shell::start_code()
560{
561 code = "";
562 code_entry_active = TRUE;
563 scope = 0;
564}
565
566//-----------------------------------------------------------------------------
567// name: continue_code()
568// desc: ...
569//-----------------------------------------------------------------------------
570void Chuck_Shell::continue_code( string & in )
571{
572 if( in.find( "{" ) != string::npos )
573 // increase the scope one level and change the prompt
574 {
575 char buf[16];
576 scope++;
577#ifndef __PLATFORM_WIN32__
578 snprintf( buf, 16, "code %2d> ", (int)scope );
579#else
580 sprintf( buf, "code %2d> ", scope);
581#endif
582 prompt = buf;
583 }
584
585 if( in.find( "}" ) != string::npos )
586 // decrease the scope one level and change the prompt
587 {
588 char buf[16];
589 scope--;
590#ifndef __PLATFORM_WIN32__
591 snprintf( buf, 16, "code %2d> ", (int)scope );
592#else
593 sprintf( buf, "code %2d> ", scope);
594#endif
595 prompt = buf;
596 }
597
598 // collect this line as ChucK code
599 code += in + "\n";
600
601 if( scope == 0 )
602 // the end of this code block -- lets execute it on the current_vm
603 code_entry_active = FALSE;
604}
605
606//-----------------------------------------------------------------------------
607// name: do_code()
608// desc: ...
609//-----------------------------------------------------------------------------
610void Chuck_Shell::do_code( string & code, string & out, string command )
611{
612 // open a temporary file
613#if defined(__PLATFORM_LINUX__) || defined(__MACOSX_CORE__)
614 char tmp_dir[] = "/tmp";
615 char * tmp_filepath = new char [32];
616 strncpy( tmp_filepath, "/tmp/chuck_file.XXXXXX", 32 );
617 int fd = mkstemp( tmp_filepath );
618 if( fd == -1 )
619 {
620 out += string( "shell: error: unable to create tmpfile at " ) + tmp_dir + "\n";
621 delete[] tmp_filepath;
622 prompt = variables["COMMAND_PROMPT"];
623 return;
624 }
625
626 FILE * tmp_file = fdopen( fd, "w+" );
627 if( tmp_file == NULL )
628 {
629 out += string( "shell: error: unable to reopen tmpfile at " ) + tmp_filepath + "\n";
630 delete[] tmp_filepath;
631 prompt = variables["COMMAND_PROMPT"];
632 return;
633 }
634#else
635 char tmp_filepath1[MAX_PATH];
636 win32_tmpnam(tmp_filepath1);
637
638 if( tmp_filepath1 == NULL )
639 {
640 out += string( "shell: error: unable to generate tmpfile name\n" );
641 prompt = variables["COMMAND_PROMPT"];
642 return;
643 }
644
645 string tmp_filepath_stl = normalize_directory_separator(string(tmp_filepath1));
646 const char *tmp_filepath = tmp_filepath_stl.c_str();
647 FILE * tmp_file = fopen( tmp_filepath, "w" );
648 if( tmp_file == NULL )
649 {
650 out += string( "shell: error: unable to open tmpfile '" ) + tmp_filepath + "'\n";
651 prompt = variables["COMMAND_PROMPT"];
652 return;
653 }
654#endif
655
656 // write the code to the temp file
657 fprintf( tmp_file, "%s", code.c_str() );
658 fclose( tmp_file );
659
660 string argv = string( command ) + tmp_filepath;
661
662 this->execute( argv, out );
663 // if( this->execute( argv, out ) )
664 // ;
665
666 // delete the file
667#ifndef __PLATFORM_WIN32__
668 unlink( tmp_filepath );
669#else
670 DeleteFile( tmp_filepath );
671#endif // __PLATFORM_WIN32__
672
673#if defined(__PLATFORM_LINUX__)
674 delete[] tmp_filepath;
675#endif
676
677 prompt = variables["COMMAND_PROMPT"];
678}
679
680//-----------------------------------------------------------------------------
681// name: do_context()
682// desc: ...
683//-----------------------------------------------------------------------------
684void Chuck_Shell::do_code_context( string & )
685{
686
687}
688
689//-----------------------------------------------------------------------------
690// name: close()
691// desc: ...
692//-----------------------------------------------------------------------------
693void Chuck_Shell::close()
694{
695 stop = TRUE;
696 //
697}
698
699//-----------------------------------------------------------------------------
700// name: kill()
701// desc: ...
702//-----------------------------------------------------------------------------
703void Chuck_Shell::exit()
704{
705 stop = TRUE;
706
707 // REFACTOR 2017 TODO Ge: all_stop
708/*
709 if( process_vm != NULL )
710 all_stop(); // ge: 1.3.5.3
711 // process_vm->stop();
712*/
713}
714
715//-----------------------------------------------------------------------------
716// name: init()
717// desc: ...
718//-----------------------------------------------------------------------------
719t_CKBOOL Chuck_Shell_Network_VM::init( const string & hostname, t_CKINT port )
720{
721 this->hostname = hostname;
722 this->port = port;
723 return TRUE;
724}
725
726//-----------------------------------------------------------------------------
727// name: copy()
728// desc: ...
729//-----------------------------------------------------------------------------
730Chuck_Shell_VM * Chuck_Shell_Network_VM::copy()
731{
732 Chuck_Shell_Network_VM * net_vm = new Chuck_Shell_Network_VM();
733 net_vm->init( hostname, port );
734 return net_vm;
735}
736
737//-----------------------------------------------------------------------------
738// name: add_shred()
739// desc: ...
740//-----------------------------------------------------------------------------
741t_CKBOOL Chuck_Shell_Network_VM::add_shred( const vector< string > & files,
742 string & out )
743{
744 t_CKINT i = 0;
745 t_CKBOOL return_val;
746 vector<string>::size_type j, str_len, vec_len = files.size() + 1;
747 const char ** argv = new const char * [ vec_len ];
748
749 /* prepare an argument vector to submit to otf_send_cmd */
750 /* first, specify an add command */
751 char * argv0 = new char [2];
752 strncpy( argv0, "+", 2 );
753 argv[0] = argv0;
754
755 /* copy file paths into argv */
756 for( j = 1; j < vec_len; j++ )
757 {
758 str_len = files[j - 1].size() + 1;
759 char * argvj = new char [str_len];
760 strncpy( argvj, files[j - 1].c_str(), str_len );
761 argv[j] = argvj;
762 }
763
764 /* send the command */
765 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
766 return_val = TRUE;
767 else
768 {
769 out += "add: error: command failed\n";
770 return_val = FALSE;
771 }
772
773 /* clean up heap data */
774 for( j = 0; j < vec_len; j++ )
775 {
776 // TODO: verify this is alright
777 char * arg = (char *)argv[j];
778 delete[] arg;
779 }
780 delete[] argv;
781
782 return return_val;
783}
784
785//-----------------------------------------------------------------------------
786// name: remove_shred()
787// desc: ...
788//-----------------------------------------------------------------------------
789t_CKBOOL Chuck_Shell_Network_VM::remove_shred( const vector< string > & ids,
790 string & out )
791{
792 t_CKINT i = 0;
793 t_CKBOOL return_val;
794 vector<string>::size_type j, str_len, vec_len = ids.size() + 1;
795 const char ** argv = new const char * [ vec_len ];
796
797 /* prepare an argument vector to submit to otf_send_cmd */
798 /* first, specify an add command */
799 char * argv0 = new char [2];
800 strncpy( argv0, "-", 2 );
801 argv[0] = argv0;
802
803 /* copy ids into argv */
804 for( j = 1; j < vec_len; j++ )
805 {
806 str_len = ids[j - 1].size() + 1;
807 char * argvj = new char [str_len];
808 strncpy( argvj, ids[j - 1].c_str(), str_len );
809 argv[j] = argvj;
810 }
811
812 /* send the command */
813 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
814 return_val = TRUE;
815 else
816 {
817 out += "remove: error: command failed\n";
818 return_val = FALSE;
819 }
820
821 /* clean up heap data */
822 for( j = 0; j < vec_len; j++ )
823 {
824 // TODO: verify this is ok
825 char * arg = (char *)argv[j];
826 delete[] arg;
827 }
828 delete[] argv;
829
830 return return_val;
831}
832
833//-----------------------------------------------------------------------------
834// name: remove_all()
835// desc: ...
836//-----------------------------------------------------------------------------
837t_CKBOOL Chuck_Shell_Network_VM::remove_all( string & out )
838{
839 t_CKBOOL return_val = TRUE;
840 t_CKINT j = 0;
841 const char * argv = "--removeall";
842 if( !otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
843 {
844 out += "removeall: error: command failed\n";
845 return_val = FALSE;
846 }
847
848 return return_val;
849}
850
851//-----------------------------------------------------------------------------
852// name: remove_last()
853// desc: ...
854//-----------------------------------------------------------------------------
855t_CKBOOL Chuck_Shell_Network_VM::remove_last( string & out )
856{
857 t_CKBOOL return_val = TRUE;
858 t_CKINT j = 0;
859 const char * argv = "--";
860 if( !otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
861 {
862 out += "removelast: error: command failed\n";
863 return_val = FALSE;
864 }
865
866 return return_val;
867}
868
869//-----------------------------------------------------------------------------
870// name: replace_shred()
871// desc: ...
872//-----------------------------------------------------------------------------
873t_CKBOOL Chuck_Shell_Network_VM::replace_shred( const vector< string > &vec,
874 string & out )
875{
876 if( vec.size() < 2 )
877 {
878 out += "replace: error: insufficient arguments...\n";
879 return FALSE;
880 }
881
882 t_CKINT i = 0;
883 t_CKBOOL return_val;
884 vector<string>::size_type j, str_len, vec_len = vec.size() + 1;
885 const char ** argv = new const char * [ vec_len ];
886
887 /* prepare an argument vector to submit to otf_send_cmd */
888 /* first, specify an add command */
889 argv[0] = "--replace";
890
891 /* copy ids/files into argv */
892 for( j = 1; j < vec_len; j++ )
893 {
894 str_len = vec[j - 1].size() + 1;
895 char * argvj = new char [str_len];
896 strncpy( argvj, vec[j - 1].c_str(), str_len );
897 argv[j] = argvj;
898 }
899
900 /* send the command */
901 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
902 return_val = TRUE;
903
904 else
905 {
906 out += "replace: error: command failed\n";
907 return_val = FALSE;
908 }
909
910 if( vec.size() % 2 != 0 )
911 {
912 out += "repalce: warning: ignoring excess arguments\n";
913 return FALSE;
914 }
915
916 /* clean up heap data */
917 for( j = 1; j < vec_len; j++ )
918 {
919 // TODO: verify this is ok
920 char * arg = (char *)argv[j];
921 delete[] arg;
922 }
923 delete[] argv;
924
925 return return_val;
926}
927
928//-----------------------------------------------------------------------------
929// name: status()
930// desc: ...
931//-----------------------------------------------------------------------------
932t_CKBOOL Chuck_Shell_Network_VM::status( string & out )
933{
934 const char * argv = "--status";
935 t_CKBOOL return_val = FALSE;
936 t_CKINT j = 0;
937
938 if( otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
939 return_val = TRUE;
940 else
941 {
942 return_val = FALSE;
943 out += "status: error: command failed\n";
944 }
945
946 return return_val;
947}
948
949//-----------------------------------------------------------------------------
950// name: kill()
951// desc: ...
952//-----------------------------------------------------------------------------
953t_CKBOOL Chuck_Shell_Network_VM::kill( string & out )
954{
955 const char * argv = "--kill";
956 t_CKINT j = 0;
957 t_CKBOOL return_val;
958
959 if( otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
960 return_val = TRUE;
961
962 else
963 {
964 return_val = FALSE;
965 out += "kill: error: command failed";
966 }
967
968 return return_val;
969}
970
971//-----------------------------------------------------------------------------
972// name: fullname()
973// desc: returns a somewhat descriptive full name for this VM
974//-----------------------------------------------------------------------------
975string Chuck_Shell_Network_VM::fullname()
976{
977 char buf[16];
978 sprintf( buf, ":%u", (int)port );
979
980 return hostname + buf;
981}
982
983//-----------------------------------------------------------------------------
984// name: init()
985// desc: ...
986//-----------------------------------------------------------------------------
987t_CKBOOL Chuck_Shell_UI::init()
988{
989 return TRUE;
990}
991
992//-----------------------------------------------------------------------------
993// name: init()
994// desc: ...
995//-----------------------------------------------------------------------------
996t_CKBOOL Chuck_Shell::Command::init( Chuck_Shell * caller )
997{
998 this->caller = caller;
999 return TRUE;
1000}
1001
1002//-----------------------------------------------------------------------------
1003// name: usage()
1004// desc: ...
1005//-----------------------------------------------------------------------------
1006string Chuck_Shell::Command::usage()
1007{
1008 return "no usage specified";
1009}
1010
1011//-----------------------------------------------------------------------------
1012// name: long_usage()
1013// desc: ...
1014//-----------------------------------------------------------------------------
1015string Chuck_Shell::Command::long_usage()
1016{
1017 return "no usage specified";
1018}
1019
1020//-----------------------------------------------------------------------------
1021// name: execute()
1022// desc: ...
1023//-----------------------------------------------------------------------------
1024t_CKINT Chuck_Shell::Command_Add::execute( vector< string > & argv,
1025 string & out )
1026{
1027 t_CKINT result = 0;
1028
1029 if( caller->current_vm == NULL)
1030 {
1031 out += "add: error: not attached to a VM\n";
1032 result = -1;
1033 }
1034
1035 else if( argv.size() < 1 )
1036 {
1037 out += "usage: " + usage() + "\n";
1038 result = -1;
1039 }
1040
1041 else
1042 {
1043 result = caller->current_vm->add_shred( argv, out );
1044 }
1045
1046 return result;
1047}
1048
1049//-----------------------------------------------------------------------------
1050// name: usage()
1051// desc: ...
1052//-----------------------------------------------------------------------------
1053string Chuck_Shell::Command_Add::usage()
1054{
1055 return "add file ...";
1056}
1057
1058//-----------------------------------------------------------------------------
1059// name: execute()
1060// desc: ...
1061//-----------------------------------------------------------------------------
1062t_CKINT Chuck_Shell::Command_Remove::execute( vector< string > & argv,
1063 string & out )
1064{
1065 t_CKINT result = 0;
1066
1067 if( caller->current_vm == NULL)
1068 {
1069 out += "remove: error: not attached to a VM\n";
1070 result = -1;
1071 }
1072
1073 else if( argv.size() < 1 )
1074 {
1075 out += "usage: " + usage() + "\n";
1076 result = -1;
1077 }
1078
1079 else
1080 result = caller->current_vm->remove_shred( argv, out );
1081
1082 return result;
1083}
1084
1085//-----------------------------------------------------------------------------
1086// name: usage()
1087// desc: ...
1088//-----------------------------------------------------------------------------
1089string Chuck_Shell::Command_Remove::usage()
1090{
1091 return "remove shred_number ...";
1092}
1093
1094//-----------------------------------------------------------------------------
1095// name: execute()
1096// desc: ...
1097//-----------------------------------------------------------------------------
1098t_CKINT Chuck_Shell::Command_Removeall::execute( vector< string > & argv,
1099 string & out )
1100{
1101 t_CKINT result = 0;
1102
1103 if( caller->current_vm == NULL)
1104 {
1105 out += "removeall: error: not attached to a VM\n";
1106 result = -1;
1107 }
1108
1109 else if( argv.size() > 0 )
1110 {
1111 out += "usage " + usage() + "\n";
1112 result = -1;
1113 }
1114
1115 else
1116 result = caller->current_vm->remove_all( out );
1117
1118 return result;
1119}
1120
1121//-----------------------------------------------------------------------------
1122// name: usage()
1123// desc: ...
1124//-----------------------------------------------------------------------------
1125string Chuck_Shell::Command_Removeall::usage()
1126{
1127 return "removeall";
1128}
1129
1130//-----------------------------------------------------------------------------
1131// name: execute()
1132// desc: ...
1133//-----------------------------------------------------------------------------
1134t_CKINT Chuck_Shell::Command_Removelast::execute( vector< string > & argv,
1135 string & out )
1136{
1137 t_CKINT result = -1;
1138
1139 if( caller->current_vm == NULL)
1140 out += "removelast: error: not attached to a VM\n";
1141 else
1142 result = caller->current_vm->remove_last( out );
1143
1144 if( argv.size() > 0 )
1145 out += "removelast: warning: ignoring excess arguments...\n";
1146
1147 return result;
1148}
1149
1150//-----------------------------------------------------------------------------
1151// name: usage()
1152// desc: ...
1153//-----------------------------------------------------------------------------
1154string Chuck_Shell::Command_Removelast::usage()
1155{
1156 return "removelast";
1157}
1158
1159//-----------------------------------------------------------------------------
1160// name: execute()
1161// desc: ...
1162//-----------------------------------------------------------------------------
1163t_CKINT Chuck_Shell::Command_Replace::execute( vector< string > & argv,
1164 string & out )
1165{
1166 if( caller->current_vm == NULL)
1167 {
1168 out += "replace: error: not attached to a VM\n";
1169 return -1;
1170 }
1171
1172 caller->current_vm->replace_shred( argv, out );
1173
1174 return 0;
1175}
1176
1177//-----------------------------------------------------------------------------
1178// name: usage()
1179// desc: ...
1180//-----------------------------------------------------------------------------
1181string Chuck_Shell::Command_Replace::usage()
1182{
1183 return "replace shred_id file ...";
1184}
1185
1186//-----------------------------------------------------------------------------
1187// name: execute()
1188// desc: ...
1189//-----------------------------------------------------------------------------
1190t_CKINT Chuck_Shell::Command_Status::execute( vector< string > & argv,
1191 string & out )
1192{
1193 t_CKINT result = 0;
1194
1195 if( caller->current_vm == NULL)
1196 {
1197 out += "status: error: not attached to a VM\n";
1198 result = -1;
1199 }
1200
1201 else if( argv.size() > 0 )
1202 {
1203 out += "usage: " + usage() + "\n";
1204 result = -1;
1205 }
1206
1207 else
1208 result = caller->current_vm->status( out );
1209
1210 return result;
1211}
1212
1213//-----------------------------------------------------------------------------
1214// name: usage()
1215// desc: ...
1216//-----------------------------------------------------------------------------
1217string Chuck_Shell::Command_Status::usage()
1218{
1219 return "status";
1220}
1221
1222//-----------------------------------------------------------------------------
1223// name: execute()
1224// desc: ...
1225//-----------------------------------------------------------------------------
1226t_CKINT Chuck_Shell::Command_Kill::execute( vector< string > & argv,
1227 string & out )
1228{
1229 caller->current_vm->kill( out );
1230 if( argv.size() > 0 )
1231 out += "kill: warning: ignoring excess arguments...\n";
1232
1233 return 0;
1234}
1235
1236//-----------------------------------------------------------------------------
1237// name: execute()
1238// desc: ...
1239//-----------------------------------------------------------------------------
1240t_CKINT Chuck_Shell::Command_Close::execute( vector< string > & argv,
1241 string & out )
1242{
1243 caller->close();
1244
1245 out += "closing chuck shell... bye!\n";
1246
1247 if( g_shell != NULL )
1248 out += "(note: in-process VM still running, hit ctrl-c to exit)\n";
1249
1250 if( argv.size() > 0 )
1251 out += "close: warning: ignoring excess arguments...\n";
1252
1253 return 0;
1254}
1255
1256//-----------------------------------------------------------------------------
1257// name: execute()
1258// desc: ...
1259//-----------------------------------------------------------------------------
1260t_CKINT Chuck_Shell::Command_Exit::execute( vector< string > & argv,
1261 string & out )
1262{
1263 caller->exit();
1264 if( argv.size() > 0 )
1265 out += "exit: warning: ignoring excess arguments...\n";
1266
1267 return 0;
1268}
1269
1270//-----------------------------------------------------------------------------
1271// name: execute()
1272// desc: ...
1273//-----------------------------------------------------------------------------
1274t_CKINT Chuck_Shell::Command_Ls::execute( vector< string > & argv,
1275 string & out )
1276{
1277#ifndef __PLATFORM_WIN32__
1278
1279 if( argv.size() == 0 )
1280 {
1281 DIR * dir_handle = opendir( "." );
1282 if( dir_handle == NULL )
1283 {
1284 out += "ls: error: unable to open directory .\n";
1285 return -1;
1286 }
1287
1288 dirent * dir_entity = readdir( dir_handle );
1289
1290 while( dir_entity != NULL )
1291 {
1292 out += string( dir_entity->d_name ) + "\n";
1293 dir_entity = readdir( dir_handle );
1294 }
1295
1296 closedir( dir_handle );
1297 return 0;
1298 }
1299
1300 int i, len = argv.size();
1301 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1302
1303 for( i = 0; i < len; i++ )
1304 {
1305 DIR * dir_handle = opendir( argv[i].c_str() );
1306 if( dir_handle == NULL )
1307 {
1308 out += "ls: error: unable to open directory " + argv[i] + "\n";
1309 continue;
1310 }
1311
1312 dirent * dir_entity = readdir( dir_handle );
1313
1314 if( print_parent_name )
1315 out += argv[i] + ":\n";
1316
1317 while( dir_entity != NULL )
1318 {
1319 out += string( dir_entity->d_name ) + "\n";
1320 dir_entity = readdir( dir_handle );
1321 }
1322
1323 if( print_parent_name )
1324 out += "\n";
1325
1326 closedir( dir_handle );
1327 }
1328
1329#else
1330
1331 if( argv.size() == 0 )
1332 {
1333 DWORD i, k = 64;
1334 LPTSTR cwd = new char [k];
1335 WIN32_FIND_DATA find_data;
1336
1337 i = GetCurrentDirectory( k - 2, cwd );
1338
1339 if( i >= k )
1340 {
1341 SAFE_DELETE_ARRAY( cwd );
1342 cwd = new char [i + 2];
1343 GetCurrentDirectory( i, cwd );
1344 }
1345
1346 i = strlen( cwd );
1347 cwd[i] = '\\';
1348 cwd[i + 1] = '*';
1349 cwd[i + 2] = 0;
1350
1351 HANDLE find_handle = FindFirstFile( cwd, &find_data );
1352
1353 out += string( find_data.cFileName ) + "\n";
1354
1355 while( FindNextFile( find_handle, &find_data ) )
1356 out += string( find_data.cFileName ) + "\n";
1357
1358 FindClose( find_handle );
1359 return 0;
1360 }
1361
1362 int i, len = argv.size();
1363 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1364
1365 for( i = 0; i < len; i++ )
1366 {
1367 int j = argv[i].size() + 3;
1368 WIN32_FIND_DATA find_data;
1369 LPTSTR dir = new char [j];
1370 strncpy( dir, argv[i].c_str(), j );
1371 dir[j - 3] = '\\';
1372 dir[j - 2] = '*';
1373 dir[j - 1] = 0;
1374
1375 if( print_parent_name )
1376 out += argv[i] + ":\n";
1377
1378 HANDLE find_handle = FindFirstFile( dir, &find_data );
1379
1380 out += string( find_data.cFileName ) + "\n";
1381
1382 while( FindNextFile( find_handle, &find_data ) )
1383 out += string( find_data.cFileName ) + "\n";
1384
1385 if( print_parent_name )
1386 out += "\n";
1387
1388 FindClose( find_handle );
1389 }
1390
1391
1392
1393#endif // __PLATFORM_WIN32__
1394 return 0;
1395}
1396
1397//-----------------------------------------------------------------------------
1398// name: execute()
1399// desc: ...
1400//-----------------------------------------------------------------------------
1401t_CKINT Chuck_Shell::Command_Cd::execute( vector< string > & argv,
1402 string & out )
1403{
1404#ifndef __PLATFORM_WIN32__
1405 if( argv.size() < 1 )
1406 {
1407 if( chdir( getenv( "HOME" ) ) )
1408 out += "cd: error: command failed\n";
1409 }
1410
1411 else
1412 {
1413 if( chdir( argv[0].c_str() ) )
1414 out += "cd: error: command failed\n";
1415 }
1416
1417#else
1418 if( argv.size() < 1 )
1419 out += "usage: " + usage() + "\n";
1420
1421 else
1422 {
1423 if( !SetCurrentDirectory( argv[0].c_str() ) )
1424 out += "cd: error: command failed\n";
1425 }
1426
1427#endif //__PLATFORM_WIN32__
1428 return 0;
1429}
1430
1431//-----------------------------------------------------------------------------
1432// name: execute()
1433// desc: ...
1434//-----------------------------------------------------------------------------
1435t_CKINT Chuck_Shell::Command_Pwd::execute( vector< string > & argv,
1436 string & out )
1437{
1438#ifndef __PLATFORM_WIN32__
1439 char * cwd = getcwd( NULL, 0 );
1440 out += string( cwd ) + "\n";
1441 free( cwd );
1442#else
1443 DWORD i, k = 256;
1444 LPTSTR cwd = new char [k];
1445 i = GetCurrentDirectory( k, cwd );
1446
1447 if( i >= k )
1448 {
1449 SAFE_DELETE_ARRAY( cwd );
1450 cwd = new char [i];
1451 GetCurrentDirectory( i, cwd );
1452 }
1453
1454 out += string( cwd ) + "\n";
1455
1456 SAFE_DELETE_ARRAY( cwd );
1457#endif
1458
1459 if( argv.size() > 0 )
1460 out += "pwd: warning: ignoring excess arguments...\n";
1461
1462 return 0;
1463}
1464
1465//-----------------------------------------------------------------------------
1466// name: execute()
1467// desc: ...
1468//-----------------------------------------------------------------------------
1469t_CKINT Chuck_Shell::Command_Alias::execute( vector< string > & argv,
1470 string & out )
1471{
1472 vector<string>::size_type i, len = argv.size();
1473 string::size_type j;
1474 string a, b;
1475
1476 for( i = 0; i < len; i++ )
1477 {
1478 j = argv[i].find( "=" );
1479
1480 // no alias assignment specified; just print the alias value if exists
1481 if( j == string::npos )
1482 {
1483 // see if the alias exists in the map
1484 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1485 out += "alias: error: alias " + argv[i] + " not found\n";
1486 else
1487 out += "alias " + argv[i] + "='" +
1488 caller->aliases[argv[i]] + "'\n";
1489 }
1490 // create the alias
1491 else
1492 {
1493 a = string( argv[i], 0, j );
1494 b = string( argv[i], j + 1, string::npos );
1495 caller->aliases[a] = b;
1496 }
1497 }
1498
1499 if( len == 0 )
1500 // no arguments specified; print the entire alias map
1501 {
1502 map< string, string>::iterator i = caller->aliases.begin(),
1503 end = caller->aliases.end();
1504 for( ; i != end; i++ )
1505 out += "alias " + i->first + "='" + i->second + "'\n";
1506 }
1507
1508 return 0;
1509}
1510
1511//-----------------------------------------------------------------------------
1512// name: execute()
1513// desc: ...
1514//-----------------------------------------------------------------------------
1515t_CKINT Chuck_Shell::Command_Unalias::execute( vector< string > & argv,
1516 string & out )
1517{
1518 vector<string>::size_type i, len = argv.size();
1519
1520 for( i = 0; i < len; i++ )
1521 {
1522 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1523 out += "error: alias " + argv[i] + " not found\n";
1524
1525 else
1526 caller->aliases.erase( argv[i] );
1527 }
1528
1529 return 0;
1530}
1531
1532//-----------------------------------------------------------------------------
1533// name: execute()
1534// desc: ...
1535//-----------------------------------------------------------------------------
1536t_CKINT Chuck_Shell::Command_Source::execute( vector< string > & argv,
1537 string & out )
1538{
1539 vector<string>::size_type i, len = argv.size();
1540 char line_buf[255];
1541 string line, temp;
1542
1543 for( i = 0; i < len; i++ )
1544 {
1545 FILE * source_file = fopen( argv[i].c_str(), "r" );
1546
1547 if( source_file == NULL )
1548 out += "error: unable to open file " + argv[i];
1549
1550 else
1551 {
1552 while( fgets( line_buf, 255, source_file ) != NULL )
1553 {
1554 line = string( line_buf );
1555 caller->execute( line, temp );
1556 out += temp;
1557 }
1558 }
1559 }
1560
1561 return 0;
1562}
1563
1564//-----------------------------------------------------------------------------
1565// name: execute()
1566// desc: ...
1567//-----------------------------------------------------------------------------
1568t_CKINT Chuck_Shell::Command_Help::execute( vector< string > & argv,
1569 string & out )
1570{
1571 out += "";
1572 return 0;
1573}
1574
1575//-----------------------------------------------------------------------------
1576// name: init()
1577// desc: ...
1578//-----------------------------------------------------------------------------
1579t_CKBOOL Chuck_Shell::Command_VM::init( Chuck_Shell * caller )
1580{
1581 Command * temp;
1582
1583 Command::init( caller );
1584
1585 temp = new Command_VMAttach();
1586 temp->init( caller );
1587 commands["attach"] = temp;
1588 commands["@"] = temp;
1589 allocated_commands.push_back( temp );
1590
1591 temp = new Command_VMAdd();
1592 temp->init( caller );
1593 commands["add"] = temp;
1594 commands["+"] = temp;
1595 allocated_commands.push_back( temp );
1596
1597 temp = new Command_VMRemove();
1598 temp->init( caller );
1599 commands["remove"] = temp;
1600 commands["-"] = temp;
1601 allocated_commands.push_back( temp );
1602
1603 temp = new Command_VMList();
1604 temp->init( caller );
1605 commands["list"] = temp;
1606 allocated_commands.push_back( temp );
1607
1608 temp = new Command_VMSwap();
1609 temp->init( caller );
1610 commands["swap"] = temp;
1611 commands["<"] = temp;
1612 commands["<-"] = temp;
1613 allocated_commands.push_back( temp );
1614
1615 temp = new Command_VMAttachAdd();
1616 temp->init( caller );
1617 commands["@+"] = temp;
1618 allocated_commands.push_back( temp );
1619
1620 return TRUE;
1621}
1622
1623//-----------------------------------------------------------------------------
1624// name: ~Command_VM()
1625// desc: ...
1626//-----------------------------------------------------------------------------
1627Chuck_Shell::Command_VM::~Command_VM()
1628{
1629 vector<string>::size_type i, len = allocated_commands.size();
1630
1631 //iterate through commands, delete the associated heap data
1632 for( i = 0; i != len; i++ )
1633 SAFE_DELETE( allocated_commands[i] );
1634}
1635
1636//-----------------------------------------------------------------------------
1637// name: execute()
1638// desc: ...
1639//-----------------------------------------------------------------------------
1640t_CKINT Chuck_Shell::Command_VM::execute( vector< string > & argv,
1641 string & out )
1642{
1643 if( argv.size() < 1)
1644 out += "usage: " + usage() + "\n";
1645
1646 else if( commands.find( argv[0] ) == commands.end() )
1647 // command doesn't exist
1648 out += "error: vm " + argv[0] + ": command not found\n";
1649
1650 else
1651 // call the mapped command
1652 {
1653 Command * command = commands[argv[0]];
1654 argv.erase( argv.begin() );
1655 command->execute( argv, out );
1656 }
1657
1658 return 0;
1659}
1660
1661//-----------------------------------------------------------------------------
1662// name: usage()
1663// desc: ...
1664//-----------------------------------------------------------------------------
1665string Chuck_Shell::Command_VM::usage()
1666{
1667 return "vm [command] [args] ...";
1668}
1669
1670//-----------------------------------------------------------------------------
1671// name: execute()
1672// desc: ...
1673//-----------------------------------------------------------------------------
1674t_CKINT Chuck_Shell::Command_VMAttach::execute( vector < string > & argv,
1675 string & out )
1676{
1677 string hostname;
1678 t_CKINT port;
1679 t_CKINT result = 0;
1680
1681 /* parse the hostname:port */
1682 if( argv.size() == 0 )
1683 /* no hostname:port specified, use default */
1684 {
1685 argv.push_back( "localhost:8888" );
1686 hostname = "localhost";
1687 port = 8888;
1688 }
1689
1690 else
1691 {
1692 string::size_type i = argv[0].find( ":" );
1693
1694 if( i == string::npos )
1695 // couldn't find a port number; use the default
1696 {
1697 hostname = argv[0];
1698 port = 8888;
1699 argv[0] += ":8888";
1700 }
1701
1702 else
1703 {
1704 port = strtol( argv[0].c_str() + i + 1, NULL, 10 );
1705 if( port == 0 )
1706 out += string( "error: invalid port '" ) +
1707 string( argv[0].c_str() + i + 1 ) + "'\n";
1708
1709 else
1710 hostname = string( argv[0], 0, i );
1711 }
1712 }
1713
1714 if( port != 0 )
1715 {
1716 //string temp;
1717
1718 Chuck_Shell_Network_VM * new_vm = new Chuck_Shell_Network_VM();
1719 new_vm->init( hostname, port );
1720
1721 /*if( !new_vm->status( temp ) )
1722 {
1723 SAFE_DELETE( new_vm );
1724 result = -1;
1725 }*/
1726
1727 SAFE_DELETE( caller->current_vm );
1728 caller->current_vm = new_vm;
1729 out += argv[0] + " is now current VM\n";
1730 result = 0;
1731 }
1732
1733 else
1734 {
1735 out += "error: unable to attach to " + argv[0] + "\n";
1736 result = -1;
1737 }
1738
1739 if( argv.size() > 1 )
1740 out += "warning: ignoring excess arguments...\n";
1741
1742 return result;
1743}
1744
1745//-----------------------------------------------------------------------------
1746// name: execute()
1747// desc: ...
1748//-----------------------------------------------------------------------------
1749t_CKINT Chuck_Shell::Command_VMAdd::execute( vector< string > & argv,
1750 string & out )
1751{
1752 char buf[16];
1753
1754 if( caller->current_vm == NULL )
1755 {
1756 out += "error: no VM to save\n";
1757 return -1;
1758 }
1759
1760 caller->vms.push_back( caller->current_vm->copy() );
1761
1762#ifndef __PLATFORM_WIN32__
1763 snprintf( buf, 16, "%lu", caller->vms.size() - 1 );
1764#else
1765 sprintf( buf, "%u", caller->vms.size() - 1 );
1766#endif // __PLATFORM_WIN32__
1767
1768 out += caller->current_vm->fullname() + " saved as VM " + buf + "\n";
1769
1770 if( argv.size() > 0 )
1771 out += "warning: ignoring excess arguments...\n";
1772
1773 return 0;
1774}
1775
1776//-----------------------------------------------------------------------------
1777// name: execute()
1778// desc: ...
1779//-----------------------------------------------------------------------------
1780t_CKINT Chuck_Shell::Command_VMRemove::execute( vector< string > & argv,
1781 string & out )
1782{
1783 vector<string>::size_type i = 0, vm_no, len = argv.size();
1784
1785 for( ; i < len; i++ )
1786 {
1787 vm_no = strtoul( argv[i].c_str(), NULL, 10 );
1788 if( ( vm_no == 0 && errno == EINVAL ) || caller->vms.size() <= vm_no ||
1789 caller->vms[vm_no] == NULL )
1790 {
1791 out += "error: invalid VM id: " + argv[i] + "\n";
1792 }
1793 else
1794 {
1795 SAFE_DELETE( caller->vms[vm_no] );
1796 }
1797 }
1798
1799 return 0;
1800}
1801
1802//-----------------------------------------------------------------------------
1803// name: execute()
1804// desc: ...
1805//-----------------------------------------------------------------------------
1806t_CKINT Chuck_Shell::Command_VMSwap::execute( vector< string > & argv,
1807 string & out )
1808{
1809 vector<string>::size_type new_vm = 0;
1810
1811 if( argv.size() < 1 )
1812 {
1813 out += string( "error: too few arguments...\n" );
1814 return -1;
1815 }
1816
1817 new_vm = strtol( argv[0].c_str(), NULL, 10 );
1818 if( new_vm >= caller->vms.size() || caller->vms[new_vm] == NULL )
1819 {
1820 out += string( "error: invalid VM: " ) + argv[0] + "\n";
1821 return -1;
1822 }
1823
1824 SAFE_DELETE( caller->current_vm );
1825 caller->current_vm = caller->vms[new_vm]->copy();
1826 out += "current VM is now " + caller->current_vm->fullname() + "\n";
1827
1828 if( argv.size() > 1 )
1829 out += "warning: ignoring excess arguments...\n";
1830
1831 return 0;
1832}
1833
1834//-----------------------------------------------------------------------------
1835// name: execute()
1836// desc: ...
1837//-----------------------------------------------------------------------------
1838t_CKINT Chuck_Shell::Command_VMList::execute( vector< string > & argv,
1839 string & out )
1840{
1841 char buf[16];
1842 vector<string>::size_type i, len = caller->vms.size();
1843
1844 if( caller->current_vm != NULL )
1845 out += string("current VM: ") + caller->current_vm->fullname() + "\n";
1846
1847 for( i = 0; i < len; i++ )
1848 {
1849 if( caller->vms[i] != NULL )
1850 {
1851#ifndef __PLATFORM_WIN32__
1852 snprintf( buf, 16, "%lu", i );
1853#else
1854 sprintf( buf, "%lu", i );
1855#endif // __PLATFORM_WIN32__
1856 out += string( "VM " ) + buf + ": " +
1857 caller->vms[i]->fullname() + "\n";
1858 }
1859 }
1860
1861 if( argv.size() > 0 )
1862 out += "warning: ignoring excess arguments...\n";
1863
1864 return 0;
1865}
1866
1867//-----------------------------------------------------------------------------
1868// name: execute()
1869// desc: ...
1870//-----------------------------------------------------------------------------
1871t_CKINT Chuck_Shell::Command_VMAttachAdd::execute( vector< string > & argv,
1872 string & out )
1873{
1874 t_CKINT result = 0;
1875 string exec = string( "vm @ " ) + ( argv.size() > 0 ? argv[0] : "" );
1876
1877 if( caller->execute( exec, out ) )
1878 {
1879 exec = "vm + ";
1880 if( caller->execute( exec, out ) )
1881 result = 0;
1882
1883 else
1884 result = -1;
1885 }
1886
1887 else
1888 result = -1;
1889
1890 return result;
1891}
1892
1893//-----------------------------------------------------------------------------
1894// name: init()
1895// desc: ...
1896//-----------------------------------------------------------------------------
1897t_CKBOOL Chuck_Shell::Command_Code::init( Chuck_Shell * caller )
1898{
1899 Command * temp;
1900
1901 Command::init( caller );
1902
1903 temp = new Command_CodeSave();
1904 temp->init( caller );
1905 commands["save"] = temp;
1906 allocated_commands.push_back( temp );
1907
1908 temp = new Command_CodeList();
1909 temp->init( caller );
1910 commands["list"] = temp;
1911 allocated_commands.push_back( temp );
1912
1913 temp = new Command_CodePrint();
1914 temp->init( caller );
1915 commands["print"] = temp;
1916 allocated_commands.push_back( temp );
1917
1918 temp = new Command_CodeDelete();
1919 temp->init( caller );
1920 commands["delete"] = temp;
1921 allocated_commands.push_back( temp );
1922
1923 temp = new Command_CodeWrite();
1924 temp->init( caller );
1925 commands["write"] = temp;
1926 allocated_commands.push_back( temp );
1927
1928 temp = new Command_CodeRead();
1929 temp->init( caller );
1930 commands["read"] = temp;
1931 allocated_commands.push_back( temp );
1932
1933 temp = new Command_CodeAdd();
1934 temp->init( caller );
1935 commands["add"] = temp;
1936 commands["+"] = temp;
1937 allocated_commands.push_back( temp );
1938
1939 return TRUE;
1940}
1941
1942//-----------------------------------------------------------------------------
1943// name: ~Command_Code()
1944// desc: ...
1945//-----------------------------------------------------------------------------
1946Chuck_Shell::Command_Code::~Command_Code()
1947{
1948 vector<string>::size_type i, len = allocated_commands.size();
1949
1950 //iterate through commands, delete the associated heap data
1951 for( i = 0; i != len; i++ )
1952 SAFE_DELETE( allocated_commands[i] );
1953}
1954
1955//-----------------------------------------------------------------------------
1956// name: execute()
1957// desc: ...
1958//-----------------------------------------------------------------------------
1959t_CKINT Chuck_Shell::Command_Code::execute( vector< string > & argv,
1960 string & out )
1961{
1962 if( argv.size() < 1)
1963 out += "usage: " + usage() + "\n";
1964
1965 else if( commands.find( argv[0] ) == commands.end() )
1966 // command doesn't exist
1967 out += "error: code " + argv[0] + ": command not found\n";
1968
1969 else
1970 {
1971 // call the mapped command
1972 Command * command = commands[argv[0]];
1973 argv.erase( argv.begin() );
1974 command->execute( argv, out );
1975 }
1976
1977 return 0;
1978}
1979
1980//-----------------------------------------------------------------------------
1981// name: usage()
1982// desc: ...
1983//-----------------------------------------------------------------------------
1984string Chuck_Shell::Command_Code::usage()
1985{
1986 return "code [command] [args] ...";
1987}
1988
1989//-----------------------------------------------------------------------------
1990// name: execute()
1991// desc: ...
1992//-----------------------------------------------------------------------------
1993t_CKINT Chuck_Shell::Command_CodeSave::execute( vector < string > & argv,
1994 string & out )
1995{
1996 if( argv.size() < 1 )
1997 {
1998 out += "error: please specify a name to identify the code\n";
1999 }
2000 else
2001 {
2002 if( caller->code == "" )
2003 out += "error: no code to save\n";
2004
2005 else
2006 caller->saved_code[argv[0]] = caller->code;
2007
2008 if( argv.size() > 1 )
2009 out += "warning: ignoring excess arguments...\n";
2010 }
2011
2012 return 0;
2013}
2014
2015//-----------------------------------------------------------------------------
2016// name: execute()
2017// desc: ...
2018//-----------------------------------------------------------------------------
2019t_CKINT Chuck_Shell::Command_CodeList::execute( vector < string > & argv,
2020 string & out )
2021{
2022 map< string, string >::iterator i = caller->saved_code.begin(),
2023 end = caller->saved_code.end();
2024 for( ; i != end; i++ )
2025 out += i->first + "\n";
2026
2027 if( argv.size() > 0 )
2028 out += "warning: ignoring excess arguments...\n";
2029
2030 return 0;
2031}
2032
2033//-----------------------------------------------------------------------------
2034// name: execute()
2035// desc: ...
2036//-----------------------------------------------------------------------------
2037t_CKINT Chuck_Shell::Command_CodeAdd::execute( vector < string > & argv,
2038 string & out )
2039{
2040 if( argv.size() == 0 )
2041 {
2042 if( caller->code != "" )
2043 caller->do_code( caller->code, out );
2044
2045 else
2046 out += "error: no code to add\n";
2047 }
2048
2049 else
2050 {
2051 vector<string>::size_type i, len;
2052 for( i = 0, len = argv.size(); i < len; i++ )
2053 {
2054 // iterate through all of the arguments, add the saved codes
2055 if( caller->saved_code.find( argv[i] ) ==
2056 caller->saved_code.end() )
2057 out += "error: code " + argv[i] + " not found\n";
2058
2059 else
2060 caller->do_code( caller->code, out );
2061 }
2062 }
2063
2064 return 0;
2065}
2066
2067//-----------------------------------------------------------------------------
2068// name: execute()
2069// desc: ...
2070//-----------------------------------------------------------------------------
2071t_CKINT Chuck_Shell::Command_CodePrint::execute( vector < string > & argv,
2072 string & out )
2073{
2074 if( argv.size() == 0 )
2075 {
2076 if( caller->code != "" )
2077 out += caller->code + "\n";
2078 else
2079 out += "error: no code to print\n";
2080 }
2081
2082 else
2083 {
2084 vector<string>::size_type i, len;
2085 for( i = 0, len = argv.size(); i < len; i++ )
2086 {
2087 if( caller->saved_code.find( argv[i] ) ==
2088 caller->saved_code.end() )
2089 {
2090 out += "error: code " + argv[i] + " not found\n";
2091 }
2092 else
2093 {
2094 string code = caller->saved_code[argv[i]];
2095
2096 out += argv[i] + ":\n";
2097 out += code + "\n";
2098 }
2099 }
2100 }
2101
2102 return 0;
2103}
2104
2105//-----------------------------------------------------------------------------
2106// name: execute()
2107// desc: ...
2108//-----------------------------------------------------------------------------
2109t_CKINT Chuck_Shell::Command_CodeDelete::execute( vector < string > & argv,
2110 string & out )
2111{
2112 if( argv.size() == 0 )
2113 {
2114 out += "error: specify the code to delete\n";
2115 }
2116 else
2117 {
2118 vector<string>::size_type i, len;
2119 for( i = 0, len = argv.size(); i < len; i++ )
2120 {
2121 if( caller->saved_code.find( argv[i] ) ==
2122 caller->saved_code.end() )
2123 out += "error: code " + argv[i] + " not found\n";
2124
2125 else
2126 {
2127 caller->saved_code.erase( argv[i] );
2128 }
2129 }
2130 }
2131
2132 return 0;
2133}
2134
2135//-----------------------------------------------------------------------------
2136// name: execute()
2137// desc: ...
2138//-----------------------------------------------------------------------------
2139t_CKINT Chuck_Shell::Command_CodeWrite::execute( vector < string > & argv,
2140 string & out )
2141{
2142 if( argv.size() < 1 )
2143 {
2144 out += "error: insufficient arguments...\n";
2145 }
2146 else
2147 {
2148 if( caller->saved_code.find( argv[0] ) == caller->saved_code.end() )
2149 {
2150 // this code doesnt exist!
2151 out += "error: code " + argv[0] + " not found\n";
2152 }
2153 else
2154 {
2155 string filename;
2156 string code = caller->saved_code[argv[0]];
2157 FILE * write_file;
2158
2159 if( argv.size() >= 2 )
2160 {
2161 // use second argument as filename
2162 filename = argv[1];
2163 }
2164 else
2165 {
2166 // append .ck to the code name to get the file name
2167 filename = argv[0] + ".ck";
2168 }
2169
2170 // open the file
2171 write_file = fopen( filename.c_str(), "w" );
2172
2173 if( write_file == NULL )
2174 {
2175 out += "error: unable to open " + filename + " for writing\n";
2176 }
2177 else
2178 {
2179 // write code to the file
2180 if( fprintf( write_file, "%s", code.c_str() ) < 0 )
2181 out += "error: unable to write to " + filename + "\n";
2182
2183 fclose( write_file );
2184 }
2185 }
2186 }
2187
2188 if( argv.size() > 2 )
2189 out += "warning: ignoring excess arguments...\n";
2190
2191 return 0;
2192}
2193
2194//-----------------------------------------------------------------------------
2195// name: execute()
2196// desc: ...
2197//-----------------------------------------------------------------------------
2198t_CKINT Chuck_Shell::Command_CodeRead::execute( vector < string > & argv,
2199 string & out )
2200{
2201 if( argv.size() < 1 )
2202 {
2203 out += "error: insufficient arguments...\n";
2204 }
2205 else
2206 {
2207 string code_name;
2208 FILE * read_file;
2209
2210 if( argv.size() >= 2 )
2211 {
2212 // use second argument as the code_name
2213 code_name = argv[1];
2214 }
2215 else
2216 {
2217 // remove the file extension to get the code_name
2218 // or use the whole filename if there is no extension
2219 string::size_type k = argv[0].rfind( "." );
2220
2221 if( k == string::npos )
2222 code_name = argv[1];
2223 else
2224 code_name = string( argv[0], 0, k );
2225 }
2226
2227 // open the file
2228 read_file = fopen( argv[0].c_str(), "r" );
2229 if( read_file == NULL )
2230 out += "error: unable to open " + argv[0] + " for reading\n";
2231
2232 else
2233 {
2234 string code = "";
2235 char buffer[256], * result = fgets( buffer, 256, read_file );
2236
2237 if( result == NULL )
2238 out += "error: unable to read " + argv[0] +
2239 ", or file is empty\n";
2240
2241 else
2242 {
2243 while( result != NULL )
2244 {
2245 code += buffer;
2246 result = fgets( buffer, 256, read_file );
2247 }
2248
2249 caller->saved_code[code_name] = code;
2250 }
2251
2252 fclose( read_file );
2253 }
2254 }
2255
2256 if( argv.size() > 2 )
2257 out += "warning: ignoring excess arguments...\n";
2258
2259 return 0;
2260}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t