*** empty log message ***
[chuck-blob.git] / v2 / chuck_shell.cpp
blobe409a4a84d8ad3a7619755c6ce31b1308d30e0f5
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
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.
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.
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 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_shell.cpp
27 // desc: ...
29 // author: Spencer Salazar (ssalazar@princeton.edu)
30 // date: Autumn 2005
31 //-----------------------------------------------------------------------------
33 #include "chuck_shell.h"
34 #include "chuck_otf.h"
35 #include "util_network.h"
37 #include <stdio.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #ifndef __PLATFORM_WIN32__
41 #include <unistd.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <dirent.h>
45 #endif
47 using namespace std;
49 // global shell pointer (lives in chuck_main)
50 extern Chuck_Shell * g_shell;
52 //-----------------------------------------------------------------------------
53 // name: tokenize_string
54 // desc: divides a string into space separated tokens, respecting single and
55 // double quotes
56 //-----------------------------------------------------------------------------
57 void tokenize_string( string str, vector< string > & tokens)
59 t_CKINT space = 1;
60 t_CKINT end_space = 0;
61 t_CKINT squote = 0;
62 t_CKINT dquote = 0;
63 t_CKINT i = 0, j = 0, len = str.size();
65 for( i = 0; i < len; i++ )
67 if( isspace( str[i] ) && space )
69 j++;
70 continue;
73 if( isspace( str[i] ) && end_space )
75 tokens.push_back( string( str, j, i - j ) );
76 j = i + 1;
77 space = 1;
78 end_space = 0;
79 continue;
82 if( str[i] == '\'' )
84 if( dquote )
85 continue;
86 if( !squote )
88 str.erase( i, 1 );
89 len--;
90 i--;
91 space = 0;
92 end_space = 0;
93 squote = 1;
94 continue;
97 else if( str[i - 1] == '\\' )
99 str.erase( i - 1, 1 );
100 len--;
101 i--;
102 continue;
105 else
107 str.erase( i, 1 );
108 len--;
109 i--;
110 squote = 0;
111 end_space = 1;
112 space = 0;
113 continue;
117 if( str[i] == '"' ) //"
119 if( squote )
120 continue;
121 if( !dquote )
123 str.erase( i, 1 );
124 i--;
125 len--;
126 space = 0;
127 end_space = 0;
128 dquote = 1;
129 continue;
132 else if( str[i - 1] == '\\' )
134 str.erase( i - 1, 1 );
135 len--;
136 i--;
137 continue;
140 else
142 str.erase( i, 1 );
143 i--;
144 len--;
145 dquote = 0;
146 end_space = 1;
147 space = 0;
148 continue;
152 if( !squote && !dquote )
154 end_space = 1;
155 space = 0;
159 if( i > j && end_space )
161 tokens.push_back( string( str, j, i - j ) );
165 //-----------------------------------------------------------------------------
166 // name: shell_cb
167 // desc: thread routine
168 //-----------------------------------------------------------------------------
169 void * shell_cb( void * p )
171 Chuck_Shell * shell;
172 // log
173 EM_log( CK_LOG_INFO, "starting thread routine for shell..." );
175 // assuming this is absolutely necessary, an assert may be better
176 assert( p != NULL );
178 shell = ( Chuck_Shell * ) p;
180 //atexit( wait_for_shell );
182 // run the shell
183 shell->run();
185 // delete and set to NULL
186 SAFE_DELETE( g_shell );
187 // perhaps let shell destructor clean up mode and ui?
189 EM_log( CK_LOG_INFO, "exiting thread routine for shell..." );
191 return NULL;
197 //-----------------------------------------------------------------------------
198 // name: Chuck_Shell()
199 // desc: ...
200 //-----------------------------------------------------------------------------
201 Chuck_Shell::Chuck_Shell()
203 ui = NULL;
204 process_vm = NULL;
205 current_vm = NULL;
206 initialized = FALSE;
207 stop = FALSE;
208 code_entry_active = FALSE;
211 //-----------------------------------------------------------------------------
212 // name: ~Chuck_Shell()
213 // desc: ...
214 //-----------------------------------------------------------------------------
215 Chuck_Shell::~Chuck_Shell()
217 vector<string>::size_type i, len = allocated_commands.size();
219 //iterate through commands, delete the associated heap data
220 for( i = 0; i != len; i++ )
221 SAFE_DELETE( allocated_commands[i] );
223 // delete ui
224 SAFE_DELETE( ui );
226 // flag
227 initialized = FALSE;
230 //-----------------------------------------------------------------------------
231 // name: init()
232 // desc: ...
233 //-----------------------------------------------------------------------------
234 t_CKBOOL Chuck_Shell::init( Chuck_VM * vm, Chuck_Shell_UI * ui )
236 // log
237 EM_log( CK_LOG_SYSTEM, "initializing chuck shell..." );
239 // check
240 if( initialized == TRUE )
242 EM_log( CK_LOG_WARNING, "chuck shell already initialized" );
243 return TRUE;
246 // ui
247 if( ui == NULL )
249 fprintf( stderr, "[chuck](via shell): NULL ui passed to Chuck_Shell::init..." );
250 return FALSE;
253 this->ui = ui;
255 process_vm = vm;
257 Chuck_Shell_Network_VM * cspv = new Chuck_Shell_Network_VM();
258 if( !cspv->init( "localhost", 8888 ) )
260 fprintf( stderr, "[chuck](via shell): error initializing process VM..." );
261 SAFE_DELETE( cspv );
262 return FALSE;
265 current_vm = cspv;
266 vms.push_back( current_vm->copy() );
268 process_vm = vm;
270 code_entry_active = FALSE;
271 code = "";
273 // init default variables
274 variables["COMMAND_PROMPT"] = "chuck %> ";
275 variables["DEFAULT_CONTEXT"] = "shell_global";
277 // initialize prompt
278 prompt = variables["COMMAND_PROMPT"];
280 Command * temp;
282 // initialize the string -> Chuck_Shell_Command map
283 temp = new Command_VM();
284 temp->init( this );
285 commands["vm"] = temp;
286 allocated_commands.push_back( temp );
288 temp = new Command_VMList();
289 temp->init( this );
290 commands["vms"] = temp;
291 allocated_commands.push_back( temp );
293 temp = new Command_Add();
294 temp->init( this );
295 commands["+"] = temp;
296 commands["add"] = temp;
297 allocated_commands.push_back( temp );
299 temp = new Command_Remove();
300 temp->init( this );
301 commands["-"] = temp;
302 commands["remove"] = temp;
303 allocated_commands.push_back( temp );
305 temp = new Command_Status();
306 temp->init( this );
307 commands["status"] = temp;
308 commands["^"] = temp;
309 allocated_commands.push_back( temp );
311 temp = new Command_Removeall();
312 temp->init( this );
313 commands["removeall"] = temp;
314 allocated_commands.push_back( temp );
316 temp = new Command_Removelast();
317 temp->init( this );
318 commands["--"] = temp;
319 allocated_commands.push_back( temp );
321 temp = new Command_Replace();
322 temp->init( this );
323 commands["replace"] = temp;
324 commands["="] = temp;
325 allocated_commands.push_back( temp );
327 temp = new Command_Close();
328 temp->init( this );
329 commands["close"] = temp;
330 allocated_commands.push_back( temp );
332 temp = new Command_Kill();
333 temp->init( this );
334 commands["kill"] = temp;
335 allocated_commands.push_back( temp );
337 temp = new Command_Exit();
338 temp->init( this );
339 commands["exit"] = temp;
340 commands["quit"] = temp;
341 allocated_commands.push_back( temp );
343 temp = new Command_Ls();
344 temp->init( this );
345 commands["ls"] = temp;
346 allocated_commands.push_back( temp );
348 temp = new Command_Pwd();
349 temp->init( this );
350 commands["pwd"] = temp;
351 allocated_commands.push_back( temp );
353 temp = new Command_Cd();
354 temp->init( this );
355 commands["cd"] = temp;
356 allocated_commands.push_back( temp );
358 temp = new Command_Alias();
359 temp->init( this );
360 commands["alias"] = temp;
361 allocated_commands.push_back( temp );
363 temp = new Command_Unalias();
364 temp->init( this );
365 commands["unalias"] = temp;
366 allocated_commands.push_back( temp );
368 temp = new Command_Source();
369 temp->init( this );
370 commands["source"] = temp;
371 commands["."] = temp;
372 allocated_commands.push_back( temp );
374 temp = new Command_Code();
375 temp->init( this );
376 commands["code"] = temp;
377 allocated_commands.push_back( temp );
379 // flag
380 initialized = TRUE;
382 return TRUE;
385 //-----------------------------------------------------------------------------
386 // name: run()
387 // desc: ...
388 //-----------------------------------------------------------------------------
389 void Chuck_Shell::run()
391 // log
392 EM_log( CK_LOG_SYSTEM, "running chuck shell..." );
394 // make sure
395 if(initialized == FALSE)
397 fprintf( stderr, "[chuck](via shell): shell not initialized...\n" );
398 return;
401 string command;
402 string result;
404 ui->next_result( "welcome to chuck shell!\n" );
405 // ui->next_result( "(type \"help\" for more information)\n" );
407 // loop
408 for( ; !stop; )
410 // get command
411 if( ui->next_command( prompt, command ) == TRUE )
413 // result.clear();
414 result = "";
416 //printf( "chuck_shell::run\n" );
418 // execute the command
419 execute( command, result );
421 // command.clear();
422 command = "";
424 // pass the result to the shell ui
425 ui->next_result( result );
427 else
428 // done
429 break;
432 // log
433 EM_log( CK_LOG_SYSTEM, "exiting chuck shell..." );
436 //-----------------------------------------------------------------------------
437 // name: execute
438 // desc: ...
439 //-----------------------------------------------------------------------------
440 t_CKBOOL Chuck_Shell::execute( string & in, string & out )
442 if( !initialized )
444 //fprintf();
445 return FALSE;
448 // vector of string tokens
449 vector< string > vec;
451 // clear the response
452 out = "";
454 // first find out if this is code to run
455 if( !code_entry_active && in[in.find_first_not_of( " \t\v\n" )] == '{' )
456 start_code();
458 if( code_entry_active )
460 continue_code( in );
462 if( code_entry_active == FALSE )
464 //strip opening and closing braces
465 string::size_type k = code.find( "{" );
466 string head = string( code, 0, k );
467 code = string( code, k + 1, code.size() - k - 1 );
469 k = code.rfind( "}" );
470 string tail = string( code, k + 1, code.size() - k - 1 );
471 code = string( code, 0, k );
473 do_code( code, out );
475 tokenize_string( tail, vec );
477 if( vec.size() > 0 )
479 string temp = "code save " + vec[0];
480 execute( temp, out );
484 return TRUE;
487 // divide the string into white space separated substrings
488 tokenize_string( in, vec );
490 // if no tokens
491 if( vec.size() == 0)
492 return TRUE;
494 // first check if the first token matches an alias
495 while( aliases.find( vec[0] ) != aliases.end() )
496 // use a while loop to handle nested aliases
498 vector< string > vec2;
499 tokenize_string( aliases[vec[0]], vec2 );
500 vec.erase( vec.begin() );
501 vec2.insert( vec2.end(), vec.begin(), vec.end() );
502 vec = vec2;
505 // locate the command
506 if( commands.find( vec[0] ) == commands.end() )
507 // command doesn't exist!
509 out += vec[0] + ": command not found\n";
510 return FALSE;
513 else
514 // execute the command
516 Command * command = commands[vec[0]];
517 vec.erase( vec.begin() );
518 if( command->execute( vec, out ) == 0 )
519 return TRUE;
521 else
522 return FALSE;
525 return TRUE;
528 //-----------------------------------------------------------------------------
529 // name: start_code()
530 // desc: ...
531 //-----------------------------------------------------------------------------
532 void Chuck_Shell::start_code()
534 code = "";
535 code_entry_active = TRUE;
536 scope = 0;
539 //-----------------------------------------------------------------------------
540 // name: continue_code()
541 // desc: ...
542 //-----------------------------------------------------------------------------
543 void Chuck_Shell::continue_code( string & in )
545 if( in.find( "{" ) != string::npos )
546 // increase the scope one level and change the prompt
548 char buf[16];
549 scope++;
550 #ifndef __PLATFORM_WIN32__
551 snprintf( buf, 16, "code %2d> ", (int)scope );
552 #else
553 sprintf( buf, "code %2d> ", scope);
554 #endif
555 prompt = buf;
558 if( in.find( "}" ) != string::npos )
559 // decrease the scope one level and change the prompt
561 char buf[16];
562 scope--;
563 #ifndef __PLATFORM_WIN32__
564 snprintf( buf, 16, "code %2d> ", (int)scope );
565 #else
566 sprintf( buf, "code %2d> ", scope);
567 #endif
568 prompt = buf;
571 // collect this line as ChucK code
572 code += in + "\n";
574 if( scope == 0 )
575 // the end of this code block -- lets execute it on the current_vm
576 code_entry_active = FALSE;
579 //-----------------------------------------------------------------------------
580 // name: do_code()
581 // desc: ...
582 //-----------------------------------------------------------------------------
583 void Chuck_Shell::do_code( string & code, string & out, string command )
585 // open a temporary file
586 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__LINUX_JACK__)
587 char tmp_dir[] = "/tmp";
588 char * tmp_filepath = new char [32];
589 strncpy( tmp_filepath, "/tmp/chuck_file.XXXXXX", 32 );
590 int fd = mkstemp( tmp_filepath );
591 if( fd == -1 )
593 out += string( "shell: error: unable to create tmpfile at " ) + tmp_dir + "\n";
594 delete[] tmp_filepath;
595 prompt = variables["COMMAND_PROMPT"];
596 return;
599 FILE * tmp_file = fdopen( fd, "w+" );
600 if( tmp_file == NULL )
602 out += string( "shell: error: unable to reopen tmpfile at " ) + tmp_filepath + "\n";
603 delete[] tmp_filepath;
604 prompt = variables["COMMAND_PROMPT"];
605 return;
607 #else
608 char * tmp_filepath = tmpnam( NULL );
609 if( tmp_filepath == NULL )
611 out += string( "shell: error: unable to generate tmpfile name\n" );
612 prompt = variables["COMMAND_PROMPT"];
613 return;
616 FILE * tmp_file = fopen( tmp_filepath, "w" );
617 if( tmp_file == NULL )
619 out += string( "shell: error: unable to open tmpfile '" ) + tmp_filepath + "'\n";
620 prompt = variables["COMMAND_PROMPT"];
621 return;
623 #endif
625 // write the code to the temp file
626 fprintf( tmp_file, "%s", code.c_str() );
627 fclose( tmp_file );
629 string argv = string( command ) + tmp_filepath;
631 this->execute( argv, out );
632 // if( this->execute( argv, out ) )
633 // ;
635 // delete the file
636 #ifndef __PLATFORM_WIN32__
637 unlink( tmp_filepath );
638 #else
639 DeleteFile( tmp_filepath );
640 #endif // __PLATFORM_WIN32__
642 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__LINUX_JACK__)
643 delete[] tmp_filepath;
644 #endif
646 prompt = variables["COMMAND_PROMPT"];
649 //-----------------------------------------------------------------------------
650 // name: do_context()
651 // desc: ...
652 //-----------------------------------------------------------------------------
653 void Chuck_Shell::do_code_context( string & )
658 //-----------------------------------------------------------------------------
659 // name: close()
660 // desc: ...
661 //-----------------------------------------------------------------------------
662 void Chuck_Shell::close()
664 stop = TRUE;
668 //-----------------------------------------------------------------------------
669 // name: kill()
670 // desc: ...
671 //-----------------------------------------------------------------------------
672 void Chuck_Shell::exit()
674 stop = TRUE;
676 if( process_vm != NULL )
677 process_vm->stop();
680 //-----------------------------------------------------------------------------
681 // name: init()
682 // desc: ...
683 //-----------------------------------------------------------------------------
684 t_CKBOOL Chuck_Shell_Network_VM::init( const string & hostname, t_CKINT port )
686 this->hostname = hostname;
687 this->port = port;
688 return TRUE;
691 //-----------------------------------------------------------------------------
692 // name: copy()
693 // desc: ...
694 //-----------------------------------------------------------------------------
695 Chuck_Shell_VM * Chuck_Shell_Network_VM::copy()
697 Chuck_Shell_Network_VM * net_vm = new Chuck_Shell_Network_VM();
698 net_vm->init( hostname, port );
699 return net_vm;
702 //-----------------------------------------------------------------------------
703 // name: add_shred()
704 // desc: ...
705 //-----------------------------------------------------------------------------
706 t_CKBOOL Chuck_Shell_Network_VM::add_shred( const vector< string > & files,
707 string & out )
709 t_CKINT i = 0;
710 t_CKBOOL return_val;
711 vector<string>::size_type j, str_len, vec_len = files.size() + 1;
712 const char ** argv = new const char * [ vec_len ];
714 /* prepare an argument vector to submit to otf_send_cmd */
715 /* first, specify an add command */
716 char * argv0 = new char [2];
717 strncpy( argv0, "+", 2 );
718 argv[0] = argv0;
720 /* copy file paths into argv */
721 for( j = 1; j < vec_len; j++ )
723 str_len = files[j - 1].size() + 1;
724 char * argvj = new char [str_len];
725 strncpy( argvj, files[j - 1].c_str(), str_len );
726 argv[j] = argvj;
729 /* send the command */
730 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
731 return_val = TRUE;
732 else
734 out += "add: error: command failed\n";
735 return_val = FALSE;
738 /* clean up heap data */
739 for( j = 0; j < vec_len; j++ )
741 // TODO: verify this is alright
742 char * arg = (char *)argv[j];
743 delete[] arg;
745 delete[] argv;
747 return return_val;
750 //-----------------------------------------------------------------------------
751 // name: remove_shred()
752 // desc: ...
753 //-----------------------------------------------------------------------------
754 t_CKBOOL Chuck_Shell_Network_VM::remove_shred( const vector< string > & ids,
755 string & out )
757 t_CKINT i = 0;
758 t_CKBOOL return_val;
759 vector<string>::size_type j, str_len, vec_len = ids.size() + 1;
760 const char ** argv = new const char * [ vec_len ];
762 /* prepare an argument vector to submit to otf_send_cmd */
763 /* first, specify an add command */
764 char * argv0 = new char [2];
765 strncpy( argv0, "-", 2 );
766 argv[0] = argv0;
768 /* copy ids into argv */
769 for( j = 1; j < vec_len; j++ )
771 str_len = ids[j - 1].size() + 1;
772 char * argvj = new char [str_len];
773 strncpy( argvj, ids[j - 1].c_str(), str_len );
774 argv[j] = argvj;
777 /* send the command */
778 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
779 return_val = TRUE;
780 else
782 out += "remove: error: command failed\n";
783 return_val = FALSE;
786 /* clean up heap data */
787 for( j = 0; j < vec_len; j++ )
789 // TODO: verify this is ok
790 char * arg = (char *)argv[j];
791 delete[] arg;
793 delete[] argv;
795 return return_val;
798 //-----------------------------------------------------------------------------
799 // name: remove_all()
800 // desc: ...
801 //-----------------------------------------------------------------------------
802 t_CKBOOL Chuck_Shell_Network_VM::remove_all( string & out )
804 t_CKBOOL return_val = TRUE;
805 t_CKINT j = 0;
806 const char * argv = "--removeall";
807 if( !otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
809 out += "removeall: error: command failed\n";
810 return_val = FALSE;
813 return return_val;
816 //-----------------------------------------------------------------------------
817 // name: remove_last()
818 // desc: ...
819 //-----------------------------------------------------------------------------
820 t_CKBOOL Chuck_Shell_Network_VM::remove_last( string & out )
822 t_CKBOOL return_val = TRUE;
823 t_CKINT j = 0;
824 const char * argv = "--";
825 if( !otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
827 out += "removelast: error: command failed\n";
828 return_val = FALSE;
831 return return_val;
834 //-----------------------------------------------------------------------------
835 // name: replace_shred()
836 // desc: ...
837 //-----------------------------------------------------------------------------
838 t_CKBOOL Chuck_Shell_Network_VM::replace_shred( const vector< string > &vec,
839 string & out )
841 if( vec.size() < 2 )
843 out += "replace: error: insufficient arguments...\n";
844 return FALSE;
847 t_CKINT i = 0;
848 t_CKBOOL return_val;
849 vector<string>::size_type j, str_len, vec_len = vec.size() + 1;
850 const char ** argv = new const char * [ vec_len ];
852 /* prepare an argument vector to submit to otf_send_cmd */
853 /* first, specify an add command */
854 argv[0] = "--replace";
856 /* copy ids/files into argv */
857 for( j = 1; j < vec_len; j++ )
859 str_len = vec[j - 1].size() + 1;
860 char * argvj = new char [str_len];
861 strncpy( argvj, vec[j - 1].c_str(), str_len );
862 argv[j] = argvj;
865 /* send the command */
866 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
867 return_val = TRUE;
869 else
871 out += "replace: error: command failed\n";
872 return_val = FALSE;
875 if( vec.size() % 2 != 0 )
877 out += "repalce: warning: ignoring excess arguments\n";
878 return FALSE;
881 /* clean up heap data */
882 for( j = 1; j < vec_len; j++ )
884 // TODO: verify this is ok
885 char * arg = (char *)argv[j];
886 delete[] arg;
888 delete[] argv;
890 return return_val;
893 //-----------------------------------------------------------------------------
894 // name: status()
895 // desc: ...
896 //-----------------------------------------------------------------------------
897 t_CKBOOL Chuck_Shell_Network_VM::status( string & out )
899 const char * argv = "--status";
900 t_CKBOOL return_val = FALSE;
901 t_CKINT j = 0;
903 if( otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
904 return_val = TRUE;
905 else
907 return_val = FALSE;
908 out += "status: error: command failed\n";
911 return return_val;
914 //-----------------------------------------------------------------------------
915 // name: kill()
916 // desc: ...
917 //-----------------------------------------------------------------------------
918 t_CKBOOL Chuck_Shell_Network_VM::kill( string & out )
920 const char * argv = "--kill";
921 t_CKINT j = 0;
922 t_CKBOOL return_val;
924 if( otf_send_cmd( 1, &argv, j, hostname.c_str(), port ) )
925 return_val = TRUE;
927 else
929 return_val = FALSE;
930 out += "kill: error: command failed";
933 return return_val;
936 //-----------------------------------------------------------------------------
937 // name: fullname()
938 // desc: returns a somewhat descriptive full name for this VM
939 //-----------------------------------------------------------------------------
940 string Chuck_Shell_Network_VM::fullname()
942 char buf[16];
943 sprintf( buf, ":%u", (int)port );
945 return hostname + buf;
948 //-----------------------------------------------------------------------------
949 // name: init()
950 // desc: ...
951 //-----------------------------------------------------------------------------
952 t_CKBOOL Chuck_Shell_UI::init()
954 return TRUE;
957 //-----------------------------------------------------------------------------
958 // name: init()
959 // desc: ...
960 //-----------------------------------------------------------------------------
961 t_CKBOOL Chuck_Shell::Command::init( Chuck_Shell * caller )
963 this->caller = caller;
964 return TRUE;
967 //-----------------------------------------------------------------------------
968 // name: usage()
969 // desc: ...
970 //-----------------------------------------------------------------------------
971 string Chuck_Shell::Command::usage()
973 return "no usage specified";
976 //-----------------------------------------------------------------------------
977 // name: long_usage()
978 // desc: ...
979 //-----------------------------------------------------------------------------
980 string Chuck_Shell::Command::long_usage()
982 return "no usage specified";
985 //-----------------------------------------------------------------------------
986 // name: execute()
987 // desc: ...
988 //-----------------------------------------------------------------------------
989 t_CKINT Chuck_Shell::Command_Add::execute( vector< string > & argv,
990 string & out )
992 t_CKINT result = 0;
994 if( caller->current_vm == NULL)
996 out += "add: error: not attached to a VM\n";
997 result = -1;
1000 else if( argv.size() < 1 )
1002 out += "usage: " + usage() + "\n";
1003 result = -1;
1006 else
1008 result = caller->current_vm->add_shred( argv, out );
1011 return result;
1014 //-----------------------------------------------------------------------------
1015 // name: usage()
1016 // desc: ...
1017 //-----------------------------------------------------------------------------
1018 string Chuck_Shell::Command_Add::usage()
1020 return "add file ...";
1023 //-----------------------------------------------------------------------------
1024 // name: execute()
1025 // desc: ...
1026 //-----------------------------------------------------------------------------
1027 t_CKINT Chuck_Shell::Command_Remove::execute( vector< string > & argv,
1028 string & out )
1030 t_CKINT result = 0;
1032 if( caller->current_vm == NULL)
1034 out += "remove: error: not attached to a VM\n";
1035 result = -1;
1038 else if( argv.size() < 1 )
1040 out += "usage: " + usage() + "\n";
1041 result = -1;
1044 else
1045 result = caller->current_vm->remove_shred( argv, out );
1047 return result;
1050 //-----------------------------------------------------------------------------
1051 // name: usage()
1052 // desc: ...
1053 //-----------------------------------------------------------------------------
1054 string Chuck_Shell::Command_Remove::usage()
1056 return "remove shred_number ...";
1059 //-----------------------------------------------------------------------------
1060 // name: execute()
1061 // desc: ...
1062 //-----------------------------------------------------------------------------
1063 t_CKINT Chuck_Shell::Command_Removeall::execute( vector< string > & argv,
1064 string & out )
1066 t_CKINT result = 0;
1068 if( caller->current_vm == NULL)
1070 out += "removeall: error: not attached to a VM\n";
1071 result = -1;
1074 else if( argv.size() > 0 )
1076 out += "usage " + usage() + "\n";
1077 result = -1;
1080 else
1081 result = caller->current_vm->remove_all( out );
1083 return result;
1086 //-----------------------------------------------------------------------------
1087 // name: usage()
1088 // desc: ...
1089 //-----------------------------------------------------------------------------
1090 string Chuck_Shell::Command_Removeall::usage()
1092 return "removeall";
1095 //-----------------------------------------------------------------------------
1096 // name: execute()
1097 // desc: ...
1098 //-----------------------------------------------------------------------------
1099 t_CKINT Chuck_Shell::Command_Removelast::execute( vector< string > & argv,
1100 string & out )
1102 t_CKINT result = -1;
1104 if( caller->current_vm == NULL)
1105 out += "removelast: error: not attached to a VM\n";
1106 else
1107 result = caller->current_vm->remove_last( out );
1109 if( argv.size() > 0 )
1110 out += "removelast: warning: ignoring excess arguments...\n";
1112 return result;
1115 //-----------------------------------------------------------------------------
1116 // name: usage()
1117 // desc: ...
1118 //-----------------------------------------------------------------------------
1119 string Chuck_Shell::Command_Removelast::usage()
1121 return "removelast";
1124 //-----------------------------------------------------------------------------
1125 // name: execute()
1126 // desc: ...
1127 //-----------------------------------------------------------------------------
1128 t_CKINT Chuck_Shell::Command_Replace::execute( vector< string > & argv,
1129 string & out )
1131 if( caller->current_vm == NULL)
1133 out += "replace: error: not attached to a VM\n";
1134 return -1;
1137 caller->current_vm->replace_shred( argv, out );
1139 return 0;
1142 //-----------------------------------------------------------------------------
1143 // name: usage()
1144 // desc: ...
1145 //-----------------------------------------------------------------------------
1146 string Chuck_Shell::Command_Replace::usage()
1148 return "replace shred_id file ...";
1151 //-----------------------------------------------------------------------------
1152 // name: execute()
1153 // desc: ...
1154 //-----------------------------------------------------------------------------
1155 t_CKINT Chuck_Shell::Command_Status::execute( vector< string > & argv,
1156 string & out )
1158 t_CKINT result = 0;
1160 if( caller->current_vm == NULL)
1162 out += "status: error: not attached to a VM\n";
1163 result = -1;
1166 else if( argv.size() > 0 )
1168 out += "usage: " + usage() + "\n";
1169 result = -1;
1172 else
1173 result = caller->current_vm->status( out );
1175 return result;
1178 //-----------------------------------------------------------------------------
1179 // name: usage()
1180 // desc: ...
1181 //-----------------------------------------------------------------------------
1182 string Chuck_Shell::Command_Status::usage()
1184 return "status";
1187 //-----------------------------------------------------------------------------
1188 // name: execute()
1189 // desc: ...
1190 //-----------------------------------------------------------------------------
1191 t_CKINT Chuck_Shell::Command_Kill::execute( vector< string > & argv,
1192 string & out )
1194 caller->current_vm->kill( out );
1195 if( argv.size() > 0 )
1196 out += "kill: warning: ignoring excess arguments...\n";
1198 return 0;
1201 //-----------------------------------------------------------------------------
1202 // name: execute()
1203 // desc: ...
1204 //-----------------------------------------------------------------------------
1205 t_CKINT Chuck_Shell::Command_Close::execute( vector< string > & argv,
1206 string & out )
1208 caller->close();
1210 out += "closing chuck shell... bye!\n";
1212 if( g_shell != NULL )
1213 out += "(note: in-process VM still running, hit ctrl-c to exit)\n";
1215 if( argv.size() > 0 )
1216 out += "close: warning: ignoring excess arguments...\n";
1218 return 0;
1221 //-----------------------------------------------------------------------------
1222 // name: execute()
1223 // desc: ...
1224 //-----------------------------------------------------------------------------
1225 t_CKINT Chuck_Shell::Command_Exit::execute( vector< string > & argv,
1226 string & out )
1228 caller->exit();
1229 if( argv.size() > 0 )
1230 out += "exit: warning: ignoring excess arguments...\n";
1232 return 0;
1235 //-----------------------------------------------------------------------------
1236 // name: execute()
1237 // desc: ...
1238 //-----------------------------------------------------------------------------
1239 t_CKINT Chuck_Shell::Command_Ls::execute( vector< string > & argv,
1240 string & out )
1242 #ifndef __PLATFORM_WIN32__
1244 if( argv.size() == 0 )
1246 DIR * dir_handle = opendir( "." );
1247 if( dir_handle == NULL )
1249 out += "ls: error: unable to open directory .\n";
1250 return -1;
1253 dirent * dir_entity = readdir( dir_handle );
1255 while( dir_entity != NULL )
1257 out += string( dir_entity->d_name ) + "\n";
1258 dir_entity = readdir( dir_handle );
1261 closedir( dir_handle );
1262 return 0;
1265 int i, len = argv.size();
1266 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1268 for( i = 0; i < len; i++ )
1270 DIR * dir_handle = opendir( argv[i].c_str() );
1271 if( dir_handle == NULL )
1273 out += "ls: error: unable to open directory " + argv[i] + "\n";
1274 continue;
1277 dirent * dir_entity = readdir( dir_handle );
1279 if( print_parent_name )
1280 out += argv[i] + ":\n";
1282 while( dir_entity != NULL )
1284 out += string( dir_entity->d_name ) + "\n";
1285 dir_entity = readdir( dir_handle );
1288 if( print_parent_name )
1289 out += "\n";
1291 closedir( dir_handle );
1294 #else
1296 if( argv.size() == 0 )
1298 DWORD i, k = 64;
1299 LPTSTR cwd = new char [k];
1300 WIN32_FIND_DATA find_data;
1302 i = GetCurrentDirectory( k - 2, cwd );
1304 if( i >= k )
1306 SAFE_DELETE_ARRAY( cwd );
1307 cwd = new char [i + 2];
1308 GetCurrentDirectory( i, cwd );
1311 i = strlen( cwd );
1312 cwd[i] = '\\';
1313 cwd[i + 1] = '*';
1314 cwd[i + 2] = 0;
1316 HANDLE find_handle = FindFirstFile( cwd, &find_data );
1318 out += string( find_data.cFileName ) + "\n";
1320 while( FindNextFile( find_handle, &find_data ) )
1321 out += string( find_data.cFileName ) + "\n";
1323 FindClose( find_handle );
1324 return 0;
1327 int i, len = argv.size();
1328 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1330 for( i = 0; i < len; i++ )
1332 int j = argv[i].size() + 3;
1333 WIN32_FIND_DATA find_data;
1334 LPTSTR dir = new char [j];
1335 strncpy( dir, argv[i].c_str(), j );
1336 dir[j - 3] = '\\';
1337 dir[j - 2] = '*';
1338 dir[j - 1] = 0;
1340 if( print_parent_name )
1341 out += argv[i] + ":\n";
1343 HANDLE find_handle = FindFirstFile( dir, &find_data );
1345 out += string( find_data.cFileName ) + "\n";
1347 while( FindNextFile( find_handle, &find_data ) )
1348 out += string( find_data.cFileName ) + "\n";
1350 if( print_parent_name )
1351 out += "\n";
1353 FindClose( find_handle );
1358 #endif // __PLATFORM_WIN32__
1359 return 0;
1362 //-----------------------------------------------------------------------------
1363 // name: execute()
1364 // desc: ...
1365 //-----------------------------------------------------------------------------
1366 t_CKINT Chuck_Shell::Command_Cd::execute( vector< string > & argv,
1367 string & out )
1369 #ifndef __PLATFORM_WIN32__
1370 if( argv.size() < 1 )
1372 if( chdir( getenv( "HOME" ) ) )
1373 out += "cd: error: command failed\n";
1376 else
1378 if( chdir( argv[0].c_str() ) )
1379 out += "cd: error: command failed\n";
1382 #else
1383 if( argv.size() < 1 )
1384 out += "usage: " + usage() + "\n";
1386 else
1388 if( !SetCurrentDirectory( argv[0].c_str() ) )
1389 out += "cd: error: command failed\n";
1392 #endif //__PLATFORM_WIN32__
1393 return 0;
1396 //-----------------------------------------------------------------------------
1397 // name: execute()
1398 // desc: ...
1399 //-----------------------------------------------------------------------------
1400 t_CKINT Chuck_Shell::Command_Pwd::execute( vector< string > & argv,
1401 string & out )
1403 #ifndef __PLATFORM_WIN32__
1404 char * cwd = getcwd( NULL, 0 );
1405 out += string( cwd ) + "\n";
1406 free( cwd );
1407 #else
1408 DWORD i, k = 256;
1409 LPTSTR cwd = new char [k];
1410 i = GetCurrentDirectory( k, cwd );
1412 if( i >= k )
1414 SAFE_DELETE_ARRAY( cwd );
1415 cwd = new char [i];
1416 GetCurrentDirectory( i, cwd );
1419 out += string( cwd ) + "\n";
1421 SAFE_DELETE_ARRAY( cwd );
1422 #endif
1424 if( argv.size() > 0 )
1425 out += "pwd: warning: ignoring excess arguments...\n";
1427 return 0;
1430 //-----------------------------------------------------------------------------
1431 // name: execute()
1432 // desc: ...
1433 //-----------------------------------------------------------------------------
1434 t_CKINT Chuck_Shell::Command_Alias::execute( vector< string > & argv,
1435 string & out )
1437 vector<string>::size_type i, len = argv.size();
1438 string::size_type j;
1439 string a, b;
1441 for( i = 0; i < len; i++ )
1443 j = argv[i].find( "=" );
1445 // no alias assignment specified; just print the alias value if exists
1446 if( j == string::npos )
1448 // see if the alias exists in the map
1449 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1450 out += "alias: error: alias " + argv[i] + " not found\n";
1451 else
1452 out += "alias " + argv[i] + "='" +
1453 caller->aliases[argv[i]] + "'\n";
1455 // create the alias
1456 else
1458 a = string( argv[i], 0, j );
1459 b = string( argv[i], j + 1, string::npos );
1460 caller->aliases[a] = b;
1464 if( len == 0 )
1465 // no arguments specified; print the entire alias map
1467 map< string, string>::iterator i = caller->aliases.begin(),
1468 end = caller->aliases.end();
1469 for( ; i != end; i++ )
1470 out += "alias " + i->first + "='" + i->second + "'\n";
1473 return 0;
1476 //-----------------------------------------------------------------------------
1477 // name: execute()
1478 // desc: ...
1479 //-----------------------------------------------------------------------------
1480 t_CKINT Chuck_Shell::Command_Unalias::execute( vector< string > & argv,
1481 string & out )
1483 vector<string>::size_type i, len = argv.size();
1485 for( i = 0; i < len; i++ )
1487 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1488 out += "error: alias " + argv[i] + " not found\n";
1490 else
1491 caller->aliases.erase( argv[i] );
1494 return 0;
1497 //-----------------------------------------------------------------------------
1498 // name: execute()
1499 // desc: ...
1500 //-----------------------------------------------------------------------------
1501 t_CKINT Chuck_Shell::Command_Source::execute( vector< string > & argv,
1502 string & out )
1504 vector<string>::size_type i, len = argv.size();
1505 char line_buf[255];
1506 string line, temp;
1508 for( i = 0; i < len; i++ )
1510 FILE * source_file = fopen( argv[i].c_str(), "r" );
1512 if( source_file == NULL )
1513 out += "error: unable to open file " + argv[i];
1515 else
1517 while( fgets( line_buf, 255, source_file ) != NULL )
1519 line = string( line_buf );
1520 caller->execute( line, temp );
1521 out += temp;
1526 return 0;
1529 //-----------------------------------------------------------------------------
1530 // name: execute()
1531 // desc: ...
1532 //-----------------------------------------------------------------------------
1533 t_CKINT Chuck_Shell::Command_Help::execute( vector< string > & argv,
1534 string & out )
1536 out += "";
1537 return 0;
1540 //-----------------------------------------------------------------------------
1541 // name: init()
1542 // desc: ...
1543 //-----------------------------------------------------------------------------
1544 t_CKBOOL Chuck_Shell::Command_VM::init( Chuck_Shell * caller )
1546 Command * temp;
1548 Command::init( caller );
1550 temp = new Command_VMAttach();
1551 temp->init( caller );
1552 commands["attach"] = temp;
1553 commands["@"] = temp;
1554 allocated_commands.push_back( temp );
1556 temp = new Command_VMAdd();
1557 temp->init( caller );
1558 commands["add"] = temp;
1559 commands["+"] = temp;
1560 allocated_commands.push_back( temp );
1562 temp = new Command_VMRemove();
1563 temp->init( caller );
1564 commands["remove"] = temp;
1565 commands["-"] = temp;
1566 allocated_commands.push_back( temp );
1568 temp = new Command_VMList();
1569 temp->init( caller );
1570 commands["list"] = temp;
1571 allocated_commands.push_back( temp );
1573 temp = new Command_VMSwap();
1574 temp->init( caller );
1575 commands["swap"] = temp;
1576 commands["<"] = temp;
1577 commands["<-"] = temp;
1578 allocated_commands.push_back( temp );
1580 temp = new Command_VMAttachAdd();
1581 temp->init( caller );
1582 commands["@+"] = temp;
1583 allocated_commands.push_back( temp );
1585 return TRUE;
1588 //-----------------------------------------------------------------------------
1589 // name: ~Command_VM()
1590 // desc: ...
1591 //-----------------------------------------------------------------------------
1592 Chuck_Shell::Command_VM::~Command_VM()
1594 vector<string>::size_type i, len = allocated_commands.size();
1596 //iterate through commands, delete the associated heap data
1597 for( i = 0; i != len; i++ )
1598 SAFE_DELETE( allocated_commands[i] );
1601 //-----------------------------------------------------------------------------
1602 // name: execute()
1603 // desc: ...
1604 //-----------------------------------------------------------------------------
1605 t_CKINT Chuck_Shell::Command_VM::execute( vector< string > & argv,
1606 string & out )
1608 if( argv.size() < 1)
1609 out += "usage: " + usage() + "\n";
1611 else if( commands.find( argv[0] ) == commands.end() )
1612 // command doesn't exist
1613 out += "error: vm " + argv[0] + ": command not found\n";
1615 else
1616 // call the mapped command
1618 Command * command = commands[argv[0]];
1619 argv.erase( argv.begin() );
1620 command->execute( argv, out );
1623 return 0;
1626 //-----------------------------------------------------------------------------
1627 // name: usage()
1628 // desc: ...
1629 //-----------------------------------------------------------------------------
1630 string Chuck_Shell::Command_VM::usage()
1632 return "vm [command] [args] ...";
1635 //-----------------------------------------------------------------------------
1636 // name: execute()
1637 // desc: ...
1638 //-----------------------------------------------------------------------------
1639 t_CKINT Chuck_Shell::Command_VMAttach::execute( vector < string > & argv,
1640 string & out )
1642 string hostname;
1643 t_CKINT port;
1644 t_CKINT result = 0;
1646 /* parse the hostname:port */
1647 if( argv.size() == 0 )
1648 /* no hostname:port specified, use default */
1650 argv.push_back( "localhost:8888" );
1651 hostname = "localhost";
1652 port = 8888;
1655 else
1657 string::size_type i = argv[0].find( ":" );
1659 if( i == string::npos )
1660 // couldn't find a port number; use the default
1662 hostname = argv[0];
1663 port = 8888;
1664 argv[0] += ":8888";
1667 else
1669 port = strtol( argv[0].c_str() + i + 1, NULL, 10 );
1670 if( port == 0 )
1671 out += string( "error: invalid port '" ) +
1672 string( argv[0].c_str() + i + 1 ) + "'\n";
1674 else
1675 hostname = string( argv[0], 0, i );
1679 if( port != 0 )
1681 //string temp;
1683 Chuck_Shell_Network_VM * new_vm = new Chuck_Shell_Network_VM();
1684 new_vm->init( hostname, port );
1686 /*if( !new_vm->status( temp ) )
1688 SAFE_DELETE( new_vm );
1689 result = -1;
1692 SAFE_DELETE( caller->current_vm );
1693 caller->current_vm = new_vm;
1694 out += argv[0] + " is now current VM\n";
1695 result = 0;
1698 else
1700 out += "error: unable to attach to " + argv[0] + "\n";
1701 result = -1;
1704 if( argv.size() > 1 )
1705 out += "warning: ignoring excess arguments...\n";
1707 return result;
1710 //-----------------------------------------------------------------------------
1711 // name: execute()
1712 // desc: ...
1713 //-----------------------------------------------------------------------------
1714 t_CKINT Chuck_Shell::Command_VMAdd::execute( vector< string > & argv,
1715 string & out )
1717 char buf[16];
1719 if( caller->current_vm == NULL )
1721 out += "error: no VM to save\n";
1722 return -1;
1725 caller->vms.push_back( caller->current_vm->copy() );
1727 #ifndef __PLATFORM_WIN32__
1728 snprintf( buf, 16, "%u", caller->vms.size() - 1 );
1729 #else
1730 sprintf( buf, "%u", caller->vms.size() - 1 );
1731 #endif // __PLATFORM_WIN32__
1733 out += caller->current_vm->fullname() + " saved as VM " + buf + "\n";
1735 if( argv.size() > 0 )
1736 out += "warning: ignoring excess arguments...\n";
1738 return 0;
1741 //-----------------------------------------------------------------------------
1742 // name: execute()
1743 // desc: ...
1744 //-----------------------------------------------------------------------------
1745 t_CKINT Chuck_Shell::Command_VMRemove::execute( vector< string > & argv,
1746 string & out )
1748 vector<string>::size_type i = 0, vm_no, len = argv.size();
1750 for( ; i < len; i++ )
1752 vm_no = strtoul( argv[i].c_str(), NULL, 10 );
1753 if( vm_no == 0 && errno == EINVAL || caller->vms.size() <= vm_no ||
1754 caller->vms[vm_no] == NULL )
1756 out += "error: invalid VM id: " + argv[i] + "\n";
1758 else
1760 SAFE_DELETE( caller->vms[vm_no] );
1764 return 0;
1767 //-----------------------------------------------------------------------------
1768 // name: execute()
1769 // desc: ...
1770 //-----------------------------------------------------------------------------
1771 t_CKINT Chuck_Shell::Command_VMSwap::execute( vector< string > & argv,
1772 string & out )
1774 vector<string>::size_type new_vm = 0;
1776 if( argv.size() < 1 )
1778 out += string( "error: too few arguments...\n" );
1779 return -1;
1782 new_vm = strtol( argv[0].c_str(), NULL, 10 );
1783 if( new_vm >= caller->vms.size() || new_vm < 0 ||
1784 caller->vms[new_vm] == NULL )
1786 out += string( "error: invalid VM: " ) + argv[0] + "\n";
1787 return -1;
1790 SAFE_DELETE( caller->current_vm );
1791 caller->current_vm = caller->vms[new_vm]->copy();
1792 out += "current VM is now " + caller->current_vm->fullname() + "\n";
1794 if( argv.size() > 1 )
1795 out += "warning: ignoring excess arguments...\n";
1797 return 0;
1800 //-----------------------------------------------------------------------------
1801 // name: execute()
1802 // desc: ...
1803 //-----------------------------------------------------------------------------
1804 t_CKINT Chuck_Shell::Command_VMList::execute( vector< string > & argv,
1805 string & out )
1807 char buf[16];
1808 vector<string>::size_type i, len = caller->vms.size();
1810 if( caller->current_vm != NULL )
1811 out += string("current VM: ") + caller->current_vm->fullname() + "\n";
1813 for( i = 0; i < len; i++ )
1815 if( caller->vms[i] != NULL )
1817 #ifndef __PLATFORM_WIN32__
1818 snprintf( buf, 16, "%u", i );
1819 #else
1820 sprintf( buf, "%u", i );
1821 #endif // __PLATFORM_WIN32__
1822 out += string( "VM " ) + buf + ": " +
1823 caller->vms[i]->fullname() + "\n";
1827 if( argv.size() > 0 )
1828 out += "warning: ignoring excess arguments...\n";
1830 return 0;
1833 //-----------------------------------------------------------------------------
1834 // name: execute()
1835 // desc: ...
1836 //-----------------------------------------------------------------------------
1837 t_CKINT Chuck_Shell::Command_VMAttachAdd::execute( vector< string > & argv,
1838 string & out )
1840 t_CKINT result = 0;
1841 string exec = string( "vm @ " ) + ( argv.size() > 0 ? argv[0] : "" );
1843 if( caller->execute( exec, out ) )
1845 exec = "vm + ";
1846 if( caller->execute( exec, out ) )
1847 result = 0;
1849 else
1850 result = -1;
1853 else
1854 result = -1;
1856 return result;
1859 //-----------------------------------------------------------------------------
1860 // name: init()
1861 // desc: ...
1862 //-----------------------------------------------------------------------------
1863 t_CKBOOL Chuck_Shell::Command_Code::init( Chuck_Shell * caller )
1865 Command * temp;
1867 Command::init( caller );
1869 temp = new Command_CodeSave();
1870 temp->init( caller );
1871 commands["save"] = temp;
1872 allocated_commands.push_back( temp );
1874 temp = new Command_CodeList();
1875 temp->init( caller );
1876 commands["list"] = temp;
1877 allocated_commands.push_back( temp );
1879 temp = new Command_CodePrint();
1880 temp->init( caller );
1881 commands["print"] = temp;
1882 allocated_commands.push_back( temp );
1884 temp = new Command_CodeDelete();
1885 temp->init( caller );
1886 commands["delete"] = temp;
1887 allocated_commands.push_back( temp );
1889 temp = new Command_CodeWrite();
1890 temp->init( caller );
1891 commands["write"] = temp;
1892 allocated_commands.push_back( temp );
1894 temp = new Command_CodeRead();
1895 temp->init( caller );
1896 commands["read"] = temp;
1897 allocated_commands.push_back( temp );
1899 temp = new Command_CodeAdd();
1900 temp->init( caller );
1901 commands["add"] = temp;
1902 commands["+"] = temp;
1903 allocated_commands.push_back( temp );
1905 return TRUE;
1908 //-----------------------------------------------------------------------------
1909 // name: ~Command_Code()
1910 // desc: ...
1911 //-----------------------------------------------------------------------------
1912 Chuck_Shell::Command_Code::~Command_Code()
1914 vector<string>::size_type i, len = allocated_commands.size();
1916 //iterate through commands, delete the associated heap data
1917 for( i = 0; i != len; i++ )
1918 SAFE_DELETE( allocated_commands[i] );
1921 //-----------------------------------------------------------------------------
1922 // name: execute()
1923 // desc: ...
1924 //-----------------------------------------------------------------------------
1925 t_CKINT Chuck_Shell::Command_Code::execute( vector< string > & argv,
1926 string & out )
1928 if( argv.size() < 1)
1929 out += "usage: " + usage() + "\n";
1931 else if( commands.find( argv[0] ) == commands.end() )
1932 // command doesn't exist
1933 out += "error: code " + argv[0] + ": command not found\n";
1935 else
1937 // call the mapped command
1938 Command * command = commands[argv[0]];
1939 argv.erase( argv.begin() );
1940 command->execute( argv, out );
1943 return 0;
1946 //-----------------------------------------------------------------------------
1947 // name: usage()
1948 // desc: ...
1949 //-----------------------------------------------------------------------------
1950 string Chuck_Shell::Command_Code::usage()
1952 return "code [command] [args] ...";
1955 //-----------------------------------------------------------------------------
1956 // name: execute()
1957 // desc: ...
1958 //-----------------------------------------------------------------------------
1959 t_CKINT Chuck_Shell::Command_CodeSave::execute( vector < string > & argv,
1960 string & out )
1962 if( argv.size() < 1 )
1964 out += "error: please specify a name to identify the code\n";
1966 else
1968 if( caller->code == "" )
1969 out += "error: no code to save\n";
1971 else
1972 caller->saved_code[argv[0]] = caller->code;
1974 if( argv.size() > 1 )
1975 out += "warning: ignoring excess arguments...\n";
1978 return 0;
1981 //-----------------------------------------------------------------------------
1982 // name: execute()
1983 // desc: ...
1984 //-----------------------------------------------------------------------------
1985 t_CKINT Chuck_Shell::Command_CodeList::execute( vector < string > & argv,
1986 string & out )
1988 map< string, string >::iterator i = caller->saved_code.begin(),
1989 end = caller->saved_code.end();
1990 for( ; i != end; i++ )
1991 out += i->first + "\n";
1993 if( argv.size() > 0 )
1994 out += "warning: ignoring excess arguments...\n";
1996 return 0;
1999 //-----------------------------------------------------------------------------
2000 // name: execute()
2001 // desc: ...
2002 //-----------------------------------------------------------------------------
2003 t_CKINT Chuck_Shell::Command_CodeAdd::execute( vector < string > & argv,
2004 string & out )
2006 if( argv.size() == 0 )
2008 if( caller->code != "" )
2009 caller->do_code( caller->code, out );
2011 else
2012 out += "error: no code to add\n";
2015 else
2017 vector<string>::size_type i, len;
2018 for( i = 0, len = argv.size(); i < len; i++ )
2020 // iterate through all of the arguments, add the saved codes
2021 if( caller->saved_code.find( argv[i] ) ==
2022 caller->saved_code.end() )
2023 out += "error: code " + argv[i] + " not found\n";
2025 else
2026 caller->do_code( caller->code, out );
2030 return 0;
2033 //-----------------------------------------------------------------------------
2034 // name: execute()
2035 // desc: ...
2036 //-----------------------------------------------------------------------------
2037 t_CKINT Chuck_Shell::Command_CodePrint::execute( vector < string > & argv,
2038 string & out )
2040 if( argv.size() == 0 )
2042 if( caller->code != "" )
2043 out += caller->code + "\n";
2044 else
2045 out += "error: no code to print\n";
2048 else
2050 vector<string>::size_type i, len;
2051 for( i = 0, len = argv.size(); i < len; i++ )
2053 if( caller->saved_code.find( argv[i] ) ==
2054 caller->saved_code.end() )
2056 out += "error: code " + argv[i] + " not found\n";
2058 else
2060 string code = caller->saved_code[argv[i]];
2062 out += argv[i] + ":\n";
2063 out += code + "\n";
2068 return 0;
2071 //-----------------------------------------------------------------------------
2072 // name: execute()
2073 // desc: ...
2074 //-----------------------------------------------------------------------------
2075 t_CKINT Chuck_Shell::Command_CodeDelete::execute( vector < string > & argv,
2076 string & out )
2078 if( argv.size() == 0 )
2080 out += "error: specify the code to delete\n";
2082 else
2084 vector<string>::size_type i, len;
2085 for( i = 0, len = argv.size(); i < len; i++ )
2087 if( caller->saved_code.find( argv[i] ) ==
2088 caller->saved_code.end() )
2089 out += "error: code " + argv[i] + " not found\n";
2091 else
2093 caller->saved_code.erase( argv[i] );
2098 return 0;
2101 //-----------------------------------------------------------------------------
2102 // name: execute()
2103 // desc: ...
2104 //-----------------------------------------------------------------------------
2105 t_CKINT Chuck_Shell::Command_CodeWrite::execute( vector < string > & argv,
2106 string & out )
2108 if( argv.size() < 1 )
2110 out += "error: insufficient arguments...\n";
2112 else
2114 if( caller->saved_code.find( argv[0] ) == caller->saved_code.end() )
2116 // this code doesnt exist!
2117 out += "error: code " + argv[0] + " not found\n";
2119 else
2121 string filename;
2122 string code = caller->saved_code[argv[0]];
2123 FILE * write_file;
2125 if( argv.size() >= 2 )
2127 // use second argument as filename
2128 filename = argv[1];
2130 else
2132 // append .ck to the code name to get the file name
2133 filename = argv[0] + ".ck";
2136 // open the file
2137 write_file = fopen( filename.c_str(), "w" );
2139 if( write_file == NULL )
2141 out += "error: unable to open " + filename + " for writing\n";
2143 else
2145 // write code to the file
2146 if( fprintf( write_file, "%s", code.c_str() ) < 0 )
2147 out += "error: unable to write to " + filename + "\n";
2149 fclose( write_file );
2154 if( argv.size() > 2 )
2155 out += "warning: ignoring excess arguments...\n";
2157 return 0;
2160 //-----------------------------------------------------------------------------
2161 // name: execute()
2162 // desc: ...
2163 //-----------------------------------------------------------------------------
2164 t_CKINT Chuck_Shell::Command_CodeRead::execute( vector < string > & argv,
2165 string & out )
2167 if( argv.size() < 1 )
2169 out += "error: insufficient arguments...\n";
2171 else
2173 string code_name;
2174 FILE * read_file;
2176 if( argv.size() >= 2 )
2178 // use second argument as the code_name
2179 code_name = argv[1];
2181 else
2183 // remove the file extension to get the code_name
2184 // or use the whole filename if there is no extension
2185 string::size_type k = argv[0].rfind( "." );
2187 if( k == string::npos )
2188 code_name = argv[1];
2189 else
2190 code_name = string( argv[0], 0, k );
2193 // open the file
2194 read_file = fopen( argv[0].c_str(), "r" );
2195 if( read_file == NULL )
2196 out += "error: unable to open " + argv[0] + " for reading\n";
2198 else
2200 string code = "";
2201 char buffer[256], * result = fgets( buffer, 256, read_file );
2203 if( result == NULL )
2204 out += "error: unable to read " + argv[0] +
2205 ", or file is empty\n";
2207 else
2209 while( result != NULL )
2211 code += buffer;
2212 result = fgets( buffer, 256, read_file );
2215 caller->saved_code[code_name] = code;
2218 fclose( read_file );
2222 if( argv.size() > 2 )
2223 out += "warning: ignoring excess arguments...\n";
2225 return 0;