*** empty log message ***
[chuck-blob.git] / v2 / chuck_shell.cpp
blob2fa1b296374805425d0b23f84e5a40c4726d5059
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 char ** argv = new char * [ vec_len ];
714 /* prepare an argument vector to submit to otf_send_cmd */
715 /* first, specify an add command */
716 argv[0] = new char [2];
717 strncpy( argv[0], "+", 2 );
719 /* copy file paths into argv */
720 for( j = 1; j < vec_len; j++ )
722 str_len = files[j - 1].size() + 1;
723 argv[j] = new char [str_len];
724 strncpy( argv[j], files[j - 1].c_str(), str_len );
727 /* send the command */
728 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
729 return_val = TRUE;
730 else
732 out += "add: error: command failed\n";
733 return_val = FALSE;
736 /* clean up heap data */
737 for( j = 0; j < vec_len; j++ )
738 delete[] argv[j];
739 delete[] argv;
741 return return_val;
744 //-----------------------------------------------------------------------------
745 // name: remove_shred()
746 // desc: ...
747 //-----------------------------------------------------------------------------
748 t_CKBOOL Chuck_Shell_Network_VM::remove_shred( const vector< string > & ids,
749 string & out )
751 t_CKINT i = 0;
752 t_CKBOOL return_val;
753 vector<string>::size_type j, str_len, vec_len = ids.size() + 1;
754 char ** argv = new char * [ vec_len ];
756 /* prepare an argument vector to submit to otf_send_cmd */
757 /* first, specify an add command */
758 argv[0] = new char [2];
759 strncpy( argv[0], "-", 2 );
761 /* copy ids into argv */
762 for( j = 1; j < vec_len; j++ )
764 str_len = ids[j - 1].size() + 1;
765 argv[j] = new char [str_len];
766 strncpy( argv[j], ids[j - 1].c_str(), str_len );
769 /* send the command */
770 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
771 return_val = TRUE;
772 else
774 out += "remove: error: command failed\n";
775 return_val = FALSE;
778 /* clean up heap data */
779 for( j = 0; j < vec_len; j++ )
780 delete[] argv[j];
781 delete[] argv;
783 return return_val;
786 //-----------------------------------------------------------------------------
787 // name: remove_all()
788 // desc: ...
789 //-----------------------------------------------------------------------------
790 t_CKBOOL Chuck_Shell_Network_VM::remove_all( string & out )
792 t_CKBOOL return_val = TRUE;
793 t_CKINT j = 0;
794 char ** argv = new char *;
795 argv[0] = "--removeall";
796 if( !otf_send_cmd( 1, argv, j, hostname.c_str(), port ) )
798 out += "removeall: error: command failed\n";
799 return_val = FALSE;
802 return return_val;
805 //-----------------------------------------------------------------------------
806 // name: remove_last()
807 // desc: ...
808 //-----------------------------------------------------------------------------
809 t_CKBOOL Chuck_Shell_Network_VM::remove_last( string & out )
811 t_CKBOOL return_val = TRUE;
812 t_CKINT j = 0;
813 char ** argv = new char *;
814 argv[0] = "--";
815 if( !otf_send_cmd( 1, argv, j, hostname.c_str(), port ) )
817 out += "removelast: error: command failed\n";
818 return_val = FALSE;
821 return return_val;
824 //-----------------------------------------------------------------------------
825 // name: replace_shred()
826 // desc: ...
827 //-----------------------------------------------------------------------------
828 t_CKBOOL Chuck_Shell_Network_VM::replace_shred( const vector< string > &vec,
829 string & out )
831 if( vec.size() < 2 )
833 out += "replace: error: insufficient arguments...\n";
834 return FALSE;
837 t_CKINT i = 0;
838 t_CKBOOL return_val;
839 vector<string>::size_type j, str_len, vec_len = vec.size() + 1;
840 char ** argv = new char * [ vec_len ];
842 /* prepare an argument vector to submit to otf_send_cmd */
843 /* first, specify an add command */
844 argv[0] = "--replace";
846 /* copy ids/files into argv */
847 for( j = 1; j < vec_len; j++ )
849 str_len = vec[j - 1].size() + 1;
850 argv[j] = new char [str_len];
851 strncpy( argv[j], vec[j - 1].c_str(), str_len );
854 /* send the command */
855 if( otf_send_cmd( vec_len, argv, i, hostname.c_str(), port ) )
856 return_val = TRUE;
858 else
860 out += "replace: error: command failed\n";
861 return_val = FALSE;
864 if( vec.size() % 2 != 0 )
866 out += "repalce: warning: ignoring excess arguments\n";
867 return FALSE;
870 /* clean up heap data */
871 for( j = 1; j < vec_len; j++ )
872 delete[] argv[j];
873 delete[] argv;
875 return return_val;
878 //-----------------------------------------------------------------------------
879 // name: status()
880 // desc: ...
881 //-----------------------------------------------------------------------------
882 t_CKBOOL Chuck_Shell_Network_VM::status( string & out )
884 char ** argv = new char *;
885 t_CKBOOL return_val = FALSE;
886 t_CKINT j = 0;
888 argv[0] = "--status";
889 if( otf_send_cmd( 1, argv, j, hostname.c_str(), port ) )
890 return_val = TRUE;
892 else
894 return_val = FALSE;
895 out += "status: error: command failed\n";
898 delete argv;
900 return return_val;
903 //-----------------------------------------------------------------------------
904 // name: kill()
905 // desc: ...
906 //-----------------------------------------------------------------------------
907 t_CKBOOL Chuck_Shell_Network_VM::kill( string & out )
909 char ** argv = new char *;
910 t_CKINT j = 0;
911 t_CKBOOL return_val;
913 argv[0] = "--kill";
915 if( otf_send_cmd( 1, argv, j, hostname.c_str(), port ) )
916 return_val = TRUE;
918 else
920 return_val = FALSE;
921 out += "kill: error: command failed";
924 delete argv;
926 return return_val;
929 //-----------------------------------------------------------------------------
930 // name: fullname()
931 // desc: returns a somewhat descriptive full name for this VM
932 //-----------------------------------------------------------------------------
933 string Chuck_Shell_Network_VM::fullname()
935 char buf[16];
936 sprintf( buf, ":%u", (int)port );
938 return hostname + buf;
941 //-----------------------------------------------------------------------------
942 // name: init()
943 // desc: ...
944 //-----------------------------------------------------------------------------
945 t_CKBOOL Chuck_Shell_UI::init()
947 return TRUE;
950 //-----------------------------------------------------------------------------
951 // name: init()
952 // desc: ...
953 //-----------------------------------------------------------------------------
954 t_CKBOOL Chuck_Shell::Command::init( Chuck_Shell * caller )
956 this->caller = caller;
957 return TRUE;
960 //-----------------------------------------------------------------------------
961 // name: usage()
962 // desc: ...
963 //-----------------------------------------------------------------------------
964 string Chuck_Shell::Command::usage()
966 return "no usage specified";
969 //-----------------------------------------------------------------------------
970 // name: long_usage()
971 // desc: ...
972 //-----------------------------------------------------------------------------
973 string Chuck_Shell::Command::long_usage()
975 return "no usage specified";
978 //-----------------------------------------------------------------------------
979 // name: execute()
980 // desc: ...
981 //-----------------------------------------------------------------------------
982 t_CKINT Chuck_Shell::Command_Add::execute( vector< string > & argv,
983 string & out )
985 t_CKINT result = 0;
987 if( caller->current_vm == NULL)
989 out += "add: error: not attached to a VM\n";
990 result = -1;
993 else if( argv.size() < 1 )
995 out += "usage: " + usage() + "\n";
996 result = -1;
999 else
1001 result = caller->current_vm->add_shred( argv, out );
1004 return result;
1007 //-----------------------------------------------------------------------------
1008 // name: usage()
1009 // desc: ...
1010 //-----------------------------------------------------------------------------
1011 string Chuck_Shell::Command_Add::usage()
1013 return "add file ...";
1016 //-----------------------------------------------------------------------------
1017 // name: execute()
1018 // desc: ...
1019 //-----------------------------------------------------------------------------
1020 t_CKINT Chuck_Shell::Command_Remove::execute( vector< string > & argv,
1021 string & out )
1023 t_CKINT result = 0;
1025 if( caller->current_vm == NULL)
1027 out += "remove: error: not attached to a VM\n";
1028 result = -1;
1031 else if( argv.size() < 1 )
1033 out += "usage: " + usage() + "\n";
1034 result = -1;
1037 else
1038 result = caller->current_vm->remove_shred( argv, out );
1040 return result;
1043 //-----------------------------------------------------------------------------
1044 // name: usage()
1045 // desc: ...
1046 //-----------------------------------------------------------------------------
1047 string Chuck_Shell::Command_Remove::usage()
1049 return "remove shred_number ...";
1052 //-----------------------------------------------------------------------------
1053 // name: execute()
1054 // desc: ...
1055 //-----------------------------------------------------------------------------
1056 t_CKINT Chuck_Shell::Command_Removeall::execute( vector< string > & argv,
1057 string & out )
1059 t_CKINT result = 0;
1061 if( caller->current_vm == NULL)
1063 out += "removeall: error: not attached to a VM\n";
1064 result = -1;
1067 else if( argv.size() > 0 )
1069 out += "usage " + usage() + "\n";
1070 result = -1;
1073 else
1074 result = caller->current_vm->remove_all( out );
1076 return result;
1079 //-----------------------------------------------------------------------------
1080 // name: usage()
1081 // desc: ...
1082 //-----------------------------------------------------------------------------
1083 string Chuck_Shell::Command_Removeall::usage()
1085 return "removeall";
1088 //-----------------------------------------------------------------------------
1089 // name: execute()
1090 // desc: ...
1091 //-----------------------------------------------------------------------------
1092 t_CKINT Chuck_Shell::Command_Removelast::execute( vector< string > & argv,
1093 string & out )
1095 t_CKINT result = -1;
1097 if( caller->current_vm == NULL)
1098 out += "removelast: error: not attached to a VM\n";
1099 else
1100 result = caller->current_vm->remove_last( out );
1102 if( argv.size() > 0 )
1103 out += "removelast: warning: ignoring excess arguments...\n";
1105 return result;
1108 //-----------------------------------------------------------------------------
1109 // name: usage()
1110 // desc: ...
1111 //-----------------------------------------------------------------------------
1112 string Chuck_Shell::Command_Removelast::usage()
1114 return "removelast";
1117 //-----------------------------------------------------------------------------
1118 // name: execute()
1119 // desc: ...
1120 //-----------------------------------------------------------------------------
1121 t_CKINT Chuck_Shell::Command_Replace::execute( vector< string > & argv,
1122 string & out )
1124 if( caller->current_vm == NULL)
1126 out += "replace: error: not attached to a VM\n";
1127 return -1;
1130 caller->current_vm->replace_shred( argv, out );
1132 return 0;
1135 //-----------------------------------------------------------------------------
1136 // name: usage()
1137 // desc: ...
1138 //-----------------------------------------------------------------------------
1139 string Chuck_Shell::Command_Replace::usage()
1141 return "replace shred_id file ...";
1144 //-----------------------------------------------------------------------------
1145 // name: execute()
1146 // desc: ...
1147 //-----------------------------------------------------------------------------
1148 t_CKINT Chuck_Shell::Command_Status::execute( vector< string > & argv,
1149 string & out )
1151 t_CKINT result = 0;
1153 if( caller->current_vm == NULL)
1155 out += "status: error: not attached to a VM\n";
1156 result = -1;
1159 else if( argv.size() > 0 )
1161 out += "usage: " + usage() + "\n";
1162 result = -1;
1165 else
1166 result = caller->current_vm->status( out );
1168 return result;
1171 //-----------------------------------------------------------------------------
1172 // name: usage()
1173 // desc: ...
1174 //-----------------------------------------------------------------------------
1175 string Chuck_Shell::Command_Status::usage()
1177 return "status";
1180 //-----------------------------------------------------------------------------
1181 // name: execute()
1182 // desc: ...
1183 //-----------------------------------------------------------------------------
1184 t_CKINT Chuck_Shell::Command_Kill::execute( vector< string > & argv,
1185 string & out )
1187 caller->current_vm->kill( out );
1188 if( argv.size() > 0 )
1189 out += "kill: warning: ignoring excess arguments...\n";
1191 return 0;
1194 //-----------------------------------------------------------------------------
1195 // name: execute()
1196 // desc: ...
1197 //-----------------------------------------------------------------------------
1198 t_CKINT Chuck_Shell::Command_Close::execute( vector< string > & argv,
1199 string & out )
1201 caller->close();
1203 out += "closing chuck shell... bye!\n";
1205 if( g_shell != NULL )
1206 out += "(note: in-process VM still running, hit ctrl-c to exit)\n";
1208 if( argv.size() > 0 )
1209 out += "close: warning: ignoring excess arguments...\n";
1211 return 0;
1214 //-----------------------------------------------------------------------------
1215 // name: execute()
1216 // desc: ...
1217 //-----------------------------------------------------------------------------
1218 t_CKINT Chuck_Shell::Command_Exit::execute( vector< string > & argv,
1219 string & out )
1221 caller->exit();
1222 if( argv.size() > 0 )
1223 out += "exit: warning: ignoring excess arguments...\n";
1225 return 0;
1228 //-----------------------------------------------------------------------------
1229 // name: execute()
1230 // desc: ...
1231 //-----------------------------------------------------------------------------
1232 t_CKINT Chuck_Shell::Command_Ls::execute( vector< string > & argv,
1233 string & out )
1235 #ifndef __PLATFORM_WIN32__
1237 if( argv.size() == 0 )
1239 DIR * dir_handle = opendir( "." );
1240 if( dir_handle == NULL )
1242 out += "ls: error: unable to open directory .\n";
1243 return -1;
1246 dirent * dir_entity = readdir( dir_handle );
1248 while( dir_entity != NULL )
1250 out += string( dir_entity->d_name ) + "\n";
1251 dir_entity = readdir( dir_handle );
1254 closedir( dir_handle );
1255 return 0;
1258 int i, len = argv.size();
1259 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1261 for( i = 0; i < len; i++ )
1263 DIR * dir_handle = opendir( argv[i].c_str() );
1264 if( dir_handle == NULL )
1266 out += "ls: error: unable to open directory " + argv[i] + "\n";
1267 continue;
1270 dirent * dir_entity = readdir( dir_handle );
1272 if( print_parent_name )
1273 out += argv[i] + ":\n";
1275 while( dir_entity != NULL )
1277 out += string( dir_entity->d_name ) + "\n";
1278 dir_entity = readdir( dir_handle );
1281 if( print_parent_name )
1282 out += "\n";
1284 closedir( dir_handle );
1287 #else
1289 if( argv.size() == 0 )
1291 DWORD i, k = 64;
1292 LPTSTR cwd = new char [k];
1293 WIN32_FIND_DATA find_data;
1295 i = GetCurrentDirectory( k - 2, cwd );
1297 if( i >= k )
1299 SAFE_DELETE_ARRAY( cwd );
1300 cwd = new char [i + 2];
1301 GetCurrentDirectory( i, cwd );
1304 i = strlen( cwd );
1305 cwd[i] = '\\';
1306 cwd[i + 1] = '*';
1307 cwd[i + 2] = 0;
1309 HANDLE find_handle = FindFirstFile( cwd, &find_data );
1311 out += string( find_data.cFileName ) + "\n";
1313 while( FindNextFile( find_handle, &find_data ) )
1314 out += string( find_data.cFileName ) + "\n";
1316 FindClose( find_handle );
1317 return 0;
1320 int i, len = argv.size();
1321 t_CKBOOL print_parent_name = len > 1 ? TRUE : FALSE;
1323 for( i = 0; i < len; i++ )
1325 int j = argv[i].size() + 3;
1326 WIN32_FIND_DATA find_data;
1327 LPTSTR dir = new char [j];
1328 strncpy( dir, argv[i].c_str(), j );
1329 dir[j - 3] = '\\';
1330 dir[j - 2] = '*';
1331 dir[j - 1] = 0;
1333 if( print_parent_name )
1334 out += argv[i] + ":\n";
1336 HANDLE find_handle = FindFirstFile( dir, &find_data );
1338 out += string( find_data.cFileName ) + "\n";
1340 while( FindNextFile( find_handle, &find_data ) )
1341 out += string( find_data.cFileName ) + "\n";
1343 if( print_parent_name )
1344 out += "\n";
1346 FindClose( find_handle );
1351 #endif // __PLATFORM_WIN32__
1352 return 0;
1355 //-----------------------------------------------------------------------------
1356 // name: execute()
1357 // desc: ...
1358 //-----------------------------------------------------------------------------
1359 t_CKINT Chuck_Shell::Command_Cd::execute( vector< string > & argv,
1360 string & out )
1362 #ifndef __PLATFORM_WIN32__
1363 if( argv.size() < 1 )
1365 if( chdir( getenv( "HOME" ) ) )
1366 out += "cd: error: command failed\n";
1369 else
1371 if( chdir( argv[0].c_str() ) )
1372 out += "cd: error: command failed\n";
1375 #else
1376 if( argv.size() < 1 )
1377 out += "usage: " + usage() + "\n";
1379 else
1381 if( !SetCurrentDirectory( argv[0].c_str() ) )
1382 out += "cd: error: command failed\n";
1385 #endif //__PLATFORM_WIN32__
1386 return 0;
1389 //-----------------------------------------------------------------------------
1390 // name: execute()
1391 // desc: ...
1392 //-----------------------------------------------------------------------------
1393 t_CKINT Chuck_Shell::Command_Pwd::execute( vector< string > & argv,
1394 string & out )
1396 #ifndef __PLATFORM_WIN32__
1397 char * cwd = getcwd( NULL, 0 );
1398 out += string( cwd ) + "\n";
1399 free( cwd );
1400 #else
1401 DWORD i, k = 256;
1402 LPTSTR cwd = new char [k];
1403 i = GetCurrentDirectory( k, cwd );
1405 if( i >= k )
1407 SAFE_DELETE_ARRAY( cwd );
1408 cwd = new char [i];
1409 GetCurrentDirectory( i, cwd );
1412 out += string( cwd ) + "\n";
1414 SAFE_DELETE_ARRAY( cwd );
1415 #endif
1417 if( argv.size() > 0 )
1418 out += "pwd: warning: ignoring excess arguments...\n";
1420 return 0;
1423 //-----------------------------------------------------------------------------
1424 // name: execute()
1425 // desc: ...
1426 //-----------------------------------------------------------------------------
1427 t_CKINT Chuck_Shell::Command_Alias::execute( vector< string > & argv,
1428 string & out )
1430 vector<string>::size_type i, len = argv.size();
1431 string::size_type j;
1432 string a, b;
1434 for( i = 0; i < len; i++ )
1436 j = argv[i].find( "=" );
1438 // no alias assignment specified; just print the alias value if exists
1439 if( j == string::npos )
1441 // see if the alias exists in the map
1442 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1443 out += "alias: error: alias " + argv[i] + " not found\n";
1444 else
1445 out += "alias " + argv[i] + "='" +
1446 caller->aliases[argv[i]] + "'\n";
1448 // create the alias
1449 else
1451 a = string( argv[i], 0, j );
1452 b = string( argv[i], j + 1, string::npos );
1453 caller->aliases[a] = b;
1457 if( len == 0 )
1458 // no arguments specified; print the entire alias map
1460 map< string, string>::iterator i = caller->aliases.begin(),
1461 end = caller->aliases.end();
1462 for( ; i != end; i++ )
1463 out += "alias " + i->first + "='" + i->second + "'\n";
1466 return 0;
1469 //-----------------------------------------------------------------------------
1470 // name: execute()
1471 // desc: ...
1472 //-----------------------------------------------------------------------------
1473 t_CKINT Chuck_Shell::Command_Unalias::execute( vector< string > & argv,
1474 string & out )
1476 vector<string>::size_type i, len = argv.size();
1478 for( i = 0; i < len; i++ )
1480 if( caller->aliases.find( argv[i] ) == caller->aliases.end() )
1481 out += "error: alias " + argv[i] + " not found\n";
1483 else
1484 caller->aliases.erase( argv[i] );
1487 return 0;
1490 //-----------------------------------------------------------------------------
1491 // name: execute()
1492 // desc: ...
1493 //-----------------------------------------------------------------------------
1494 t_CKINT Chuck_Shell::Command_Source::execute( vector< string > & argv,
1495 string & out )
1497 vector<string>::size_type i, len = argv.size();
1498 char line_buf[255];
1499 string line, temp;
1501 for( i = 0; i < len; i++ )
1503 FILE * source_file = fopen( argv[i].c_str(), "r" );
1505 if( source_file == NULL )
1506 out += "error: unable to open file " + argv[i];
1508 else
1510 while( fgets( line_buf, 255, source_file ) != NULL )
1512 line = string( line_buf );
1513 caller->execute( line, temp );
1514 out += temp;
1519 return 0;
1522 //-----------------------------------------------------------------------------
1523 // name: execute()
1524 // desc: ...
1525 //-----------------------------------------------------------------------------
1526 t_CKINT Chuck_Shell::Command_Help::execute( vector< string > & argv,
1527 string & out )
1529 out += "";
1530 return 0;
1533 //-----------------------------------------------------------------------------
1534 // name: init()
1535 // desc: ...
1536 //-----------------------------------------------------------------------------
1537 t_CKBOOL Chuck_Shell::Command_VM::init( Chuck_Shell * caller )
1539 Command * temp;
1541 Command::init( caller );
1543 temp = new Command_VMAttach();
1544 temp->init( caller );
1545 commands["attach"] = temp;
1546 commands["@"] = temp;
1547 allocated_commands.push_back( temp );
1549 temp = new Command_VMAdd();
1550 temp->init( caller );
1551 commands["add"] = temp;
1552 commands["+"] = temp;
1553 allocated_commands.push_back( temp );
1555 temp = new Command_VMRemove();
1556 temp->init( caller );
1557 commands["remove"] = temp;
1558 commands["-"] = temp;
1559 allocated_commands.push_back( temp );
1561 temp = new Command_VMList();
1562 temp->init( caller );
1563 commands["list"] = temp;
1564 allocated_commands.push_back( temp );
1566 temp = new Command_VMSwap();
1567 temp->init( caller );
1568 commands["swap"] = temp;
1569 commands["<"] = temp;
1570 commands["<-"] = temp;
1571 allocated_commands.push_back( temp );
1573 temp = new Command_VMAttachAdd();
1574 temp->init( caller );
1575 commands["@+"] = temp;
1576 allocated_commands.push_back( temp );
1578 return TRUE;
1581 //-----------------------------------------------------------------------------
1582 // name: ~Command_VM()
1583 // desc: ...
1584 //-----------------------------------------------------------------------------
1585 Chuck_Shell::Command_VM::~Command_VM()
1587 vector<string>::size_type i, len = allocated_commands.size();
1589 //iterate through commands, delete the associated heap data
1590 for( i = 0; i != len; i++ )
1591 SAFE_DELETE( allocated_commands[i] );
1594 //-----------------------------------------------------------------------------
1595 // name: execute()
1596 // desc: ...
1597 //-----------------------------------------------------------------------------
1598 t_CKINT Chuck_Shell::Command_VM::execute( vector< string > & argv,
1599 string & out )
1601 if( argv.size() < 1)
1602 out += "usage: " + usage() + "\n";
1604 else if( commands.find( argv[0] ) == commands.end() )
1605 // command doesn't exist
1606 out += "error: vm " + argv[0] + ": command not found\n";
1608 else
1609 // call the mapped command
1611 Command * command = commands[argv[0]];
1612 argv.erase( argv.begin() );
1613 command->execute( argv, out );
1616 return 0;
1619 //-----------------------------------------------------------------------------
1620 // name: usage()
1621 // desc: ...
1622 //-----------------------------------------------------------------------------
1623 string Chuck_Shell::Command_VM::usage()
1625 return "vm [command] [args] ...";
1628 //-----------------------------------------------------------------------------
1629 // name: execute()
1630 // desc: ...
1631 //-----------------------------------------------------------------------------
1632 t_CKINT Chuck_Shell::Command_VMAttach::execute( vector < string > & argv,
1633 string & out )
1635 string hostname;
1636 t_CKINT port;
1637 t_CKINT result = 0;
1639 /* parse the hostname:port */
1640 if( argv.size() == 0 )
1641 /* no hostname:port specified, use default */
1643 argv.push_back( "localhost:8888" );
1644 hostname = "localhost";
1645 port = 8888;
1648 else
1650 string::size_type i = argv[0].find( ":" );
1652 if( i == string::npos )
1653 // couldn't find a port number; use the default
1655 hostname = argv[0];
1656 port = 8888;
1657 argv[0] += ":8888";
1660 else
1662 port = strtol( argv[0].c_str() + i + 1, NULL, 10 );
1663 if( port == 0 )
1664 out += string( "error: invalid port '" ) +
1665 string( argv[0].c_str() + i + 1 ) + "'\n";
1667 else
1668 hostname = string( argv[0], 0, i );
1672 if( port != 0 )
1674 //string temp;
1676 Chuck_Shell_Network_VM * new_vm = new Chuck_Shell_Network_VM();
1677 new_vm->init( hostname, port );
1679 /*if( !new_vm->status( temp ) )
1681 SAFE_DELETE( new_vm );
1682 result = -1;
1685 SAFE_DELETE( caller->current_vm );
1686 caller->current_vm = new_vm;
1687 out += argv[0] + " is now current VM\n";
1688 result = 0;
1691 else
1693 out += "error: unable to attach to " + argv[0] + "\n";
1694 result = -1;
1697 if( argv.size() > 1 )
1698 out += "warning: ignoring excess arguments...\n";
1700 return result;
1703 //-----------------------------------------------------------------------------
1704 // name: execute()
1705 // desc: ...
1706 //-----------------------------------------------------------------------------
1707 t_CKINT Chuck_Shell::Command_VMAdd::execute( vector< string > & argv,
1708 string & out )
1710 char buf[16];
1712 if( caller->current_vm == NULL )
1714 out += "error: no VM to save\n";
1715 return -1;
1718 caller->vms.push_back( caller->current_vm->copy() );
1720 #ifndef __PLATFORM_WIN32__
1721 snprintf( buf, 16, "%u", caller->vms.size() - 1 );
1722 #else
1723 sprintf( buf, "%u", caller->vms.size() - 1 );
1724 #endif // __PLATFORM_WIN32__
1726 out += caller->current_vm->fullname() + " saved as VM " + buf + "\n";
1728 if( argv.size() > 0 )
1729 out += "warning: ignoring excess arguments...\n";
1731 return 0;
1734 //-----------------------------------------------------------------------------
1735 // name: execute()
1736 // desc: ...
1737 //-----------------------------------------------------------------------------
1738 t_CKINT Chuck_Shell::Command_VMRemove::execute( vector< string > & argv,
1739 string & out )
1741 vector<string>::size_type i = 0, vm_no, len = argv.size();
1743 for( ; i < len; i++ )
1745 vm_no = strtoul( argv[i].c_str(), NULL, 10 );
1746 if( vm_no == 0 && errno == EINVAL || caller->vms.size() <= vm_no ||
1747 caller->vms[vm_no] == NULL )
1749 out += "error: invalid VM id: " + argv[i] + "\n";
1751 else
1753 SAFE_DELETE( caller->vms[vm_no] );
1757 return 0;
1760 //-----------------------------------------------------------------------------
1761 // name: execute()
1762 // desc: ...
1763 //-----------------------------------------------------------------------------
1764 t_CKINT Chuck_Shell::Command_VMSwap::execute( vector< string > & argv,
1765 string & out )
1767 vector<string>::size_type new_vm = 0;
1769 if( argv.size() < 1 )
1771 out += string( "error: too few arguments...\n" );
1772 return -1;
1775 new_vm = strtol( argv[0].c_str(), NULL, 10 );
1776 if( new_vm >= caller->vms.size() || new_vm < 0 ||
1777 caller->vms[new_vm] == NULL )
1779 out += string( "error: invalid VM: " ) + argv[0] + "\n";
1780 return -1;
1783 SAFE_DELETE( caller->current_vm );
1784 caller->current_vm = caller->vms[new_vm]->copy();
1785 out += "current VM is now " + caller->current_vm->fullname() + "\n";
1787 if( argv.size() > 1 )
1788 out += "warning: ignoring excess arguments...\n";
1790 return 0;
1793 //-----------------------------------------------------------------------------
1794 // name: execute()
1795 // desc: ...
1796 //-----------------------------------------------------------------------------
1797 t_CKINT Chuck_Shell::Command_VMList::execute( vector< string > & argv,
1798 string & out )
1800 char buf[16];
1801 vector<string>::size_type i, len = caller->vms.size();
1803 if( caller->current_vm != NULL )
1804 out += string("current VM: ") + caller->current_vm->fullname() + "\n";
1806 for( i = 0; i < len; i++ )
1808 if( caller->vms[i] != NULL )
1810 #ifndef __PLATFORM_WIN32__
1811 snprintf( buf, 16, "%u", i );
1812 #else
1813 sprintf( buf, "%u", i );
1814 #endif // __PLATFORM_WIN32__
1815 out += string( "VM " ) + buf + ": " +
1816 caller->vms[i]->fullname() + "\n";
1820 if( argv.size() > 0 )
1821 out += "warning: ignoring excess arguments...\n";
1823 return 0;
1826 //-----------------------------------------------------------------------------
1827 // name: execute()
1828 // desc: ...
1829 //-----------------------------------------------------------------------------
1830 t_CKINT Chuck_Shell::Command_VMAttachAdd::execute( vector< string > & argv,
1831 string & out )
1833 t_CKINT result = 0;
1834 string exec = string( "vm @ " ) + ( argv.size() > 0 ? argv[0] : "" );
1836 if( caller->execute( exec, out ) )
1838 exec = "vm + ";
1839 if( caller->execute( exec, out ) )
1840 result = 0;
1842 else
1843 result = -1;
1846 else
1847 result = -1;
1849 return result;
1852 //-----------------------------------------------------------------------------
1853 // name: init()
1854 // desc: ...
1855 //-----------------------------------------------------------------------------
1856 t_CKBOOL Chuck_Shell::Command_Code::init( Chuck_Shell * caller )
1858 Command * temp;
1860 Command::init( caller );
1862 temp = new Command_CodeSave();
1863 temp->init( caller );
1864 commands["save"] = temp;
1865 allocated_commands.push_back( temp );
1867 temp = new Command_CodeList();
1868 temp->init( caller );
1869 commands["list"] = temp;
1870 allocated_commands.push_back( temp );
1872 temp = new Command_CodePrint();
1873 temp->init( caller );
1874 commands["print"] = temp;
1875 allocated_commands.push_back( temp );
1877 temp = new Command_CodeDelete();
1878 temp->init( caller );
1879 commands["delete"] = temp;
1880 allocated_commands.push_back( temp );
1882 temp = new Command_CodeWrite();
1883 temp->init( caller );
1884 commands["write"] = temp;
1885 allocated_commands.push_back( temp );
1887 temp = new Command_CodeRead();
1888 temp->init( caller );
1889 commands["read"] = temp;
1890 allocated_commands.push_back( temp );
1892 temp = new Command_CodeAdd();
1893 temp->init( caller );
1894 commands["add"] = temp;
1895 commands["+"] = temp;
1896 allocated_commands.push_back( temp );
1898 return TRUE;
1901 //-----------------------------------------------------------------------------
1902 // name: ~Command_Code()
1903 // desc: ...
1904 //-----------------------------------------------------------------------------
1905 Chuck_Shell::Command_Code::~Command_Code()
1907 vector<string>::size_type i, len = allocated_commands.size();
1909 //iterate through commands, delete the associated heap data
1910 for( i = 0; i != len; i++ )
1911 SAFE_DELETE( allocated_commands[i] );
1914 //-----------------------------------------------------------------------------
1915 // name: execute()
1916 // desc: ...
1917 //-----------------------------------------------------------------------------
1918 t_CKINT Chuck_Shell::Command_Code::execute( vector< string > & argv,
1919 string & out )
1921 if( argv.size() < 1)
1922 out += "usage: " + usage() + "\n";
1924 else if( commands.find( argv[0] ) == commands.end() )
1925 // command doesn't exist
1926 out += "error: code " + argv[0] + ": command not found\n";
1928 else
1930 // call the mapped command
1931 Command * command = commands[argv[0]];
1932 argv.erase( argv.begin() );
1933 command->execute( argv, out );
1936 return 0;
1939 //-----------------------------------------------------------------------------
1940 // name: usage()
1941 // desc: ...
1942 //-----------------------------------------------------------------------------
1943 string Chuck_Shell::Command_Code::usage()
1945 return "code [command] [args] ...";
1948 //-----------------------------------------------------------------------------
1949 // name: execute()
1950 // desc: ...
1951 //-----------------------------------------------------------------------------
1952 t_CKINT Chuck_Shell::Command_CodeSave::execute( vector < string > & argv,
1953 string & out )
1955 if( argv.size() < 1 )
1957 out += "error: please specify a name to identify the code\n";
1959 else
1961 if( caller->code == "" )
1962 out += "error: no code to save\n";
1964 else
1965 caller->saved_code[argv[0]] = caller->code;
1967 if( argv.size() > 1 )
1968 out += "warning: ignoring excess arguments...\n";
1971 return 0;
1974 //-----------------------------------------------------------------------------
1975 // name: execute()
1976 // desc: ...
1977 //-----------------------------------------------------------------------------
1978 t_CKINT Chuck_Shell::Command_CodeList::execute( vector < string > & argv,
1979 string & out )
1981 map< string, string >::iterator i = caller->saved_code.begin(),
1982 end = caller->saved_code.end();
1983 for( ; i != end; i++ )
1984 out += i->first + "\n";
1986 if( argv.size() > 0 )
1987 out += "warning: ignoring excess arguments...\n";
1989 return 0;
1992 //-----------------------------------------------------------------------------
1993 // name: execute()
1994 // desc: ...
1995 //-----------------------------------------------------------------------------
1996 t_CKINT Chuck_Shell::Command_CodeAdd::execute( vector < string > & argv,
1997 string & out )
1999 if( argv.size() == 0 )
2001 if( caller->code != "" )
2002 caller->do_code( caller->code, out );
2004 else
2005 out += "error: no code to add\n";
2008 else
2010 vector<string>::size_type i, len;
2011 for( i = 0, len = argv.size(); i < len; i++ )
2013 // iterate through all of the arguments, add the saved codes
2014 if( caller->saved_code.find( argv[i] ) ==
2015 caller->saved_code.end() )
2016 out += "error: code " + argv[i] + " not found\n";
2018 else
2019 caller->do_code( caller->code, out );
2023 return 0;
2026 //-----------------------------------------------------------------------------
2027 // name: execute()
2028 // desc: ...
2029 //-----------------------------------------------------------------------------
2030 t_CKINT Chuck_Shell::Command_CodePrint::execute( vector < string > & argv,
2031 string & out )
2033 if( argv.size() == 0 )
2035 if( caller->code != "" )
2036 out += caller->code + "\n";
2037 else
2038 out += "error: no code to print\n";
2041 else
2043 vector<string>::size_type i, len;
2044 for( i = 0, len = argv.size(); i < len; i++ )
2046 if( caller->saved_code.find( argv[i] ) ==
2047 caller->saved_code.end() )
2049 out += "error: code " + argv[i] + " not found\n";
2051 else
2053 string code = caller->saved_code[argv[i]];
2055 out += argv[i] + ":\n";
2056 out += code + "\n";
2061 return 0;
2064 //-----------------------------------------------------------------------------
2065 // name: execute()
2066 // desc: ...
2067 //-----------------------------------------------------------------------------
2068 t_CKINT Chuck_Shell::Command_CodeDelete::execute( vector < string > & argv,
2069 string & out )
2071 if( argv.size() == 0 )
2073 out += "error: specify the code to delete\n";
2075 else
2077 vector<string>::size_type i, len;
2078 for( i = 0, len = argv.size(); i < len; i++ )
2080 if( caller->saved_code.find( argv[i] ) ==
2081 caller->saved_code.end() )
2082 out += "error: code " + argv[i] + " not found\n";
2084 else
2086 caller->saved_code.erase( argv[i] );
2091 return 0;
2094 //-----------------------------------------------------------------------------
2095 // name: execute()
2096 // desc: ...
2097 //-----------------------------------------------------------------------------
2098 t_CKINT Chuck_Shell::Command_CodeWrite::execute( vector < string > & argv,
2099 string & out )
2101 if( argv.size() < 1 )
2103 out += "error: insufficient arguments...\n";
2105 else
2107 if( caller->saved_code.find( argv[0] ) == caller->saved_code.end() )
2109 // this code doesnt exist!
2110 out += "error: code " + argv[0] + " not found\n";
2112 else
2114 string filename;
2115 string code = caller->saved_code[argv[0]];
2116 FILE * write_file;
2118 if( argv.size() >= 2 )
2120 // use second argument as filename
2121 filename = argv[1];
2123 else
2125 // append .ck to the code name to get the file name
2126 filename = argv[0] + ".ck";
2129 // open the file
2130 write_file = fopen( filename.c_str(), "w" );
2132 if( write_file == NULL )
2134 out += "error: unable to open " + filename + " for writing\n";
2136 else
2138 // write code to the file
2139 if( fprintf( write_file, "%s", code.c_str() ) < 0 )
2140 out += "error: unable to write to " + filename + "\n";
2142 fclose( write_file );
2147 if( argv.size() > 2 )
2148 out += "warning: ignoring excess arguments...\n";
2150 return 0;
2153 //-----------------------------------------------------------------------------
2154 // name: execute()
2155 // desc: ...
2156 //-----------------------------------------------------------------------------
2157 t_CKINT Chuck_Shell::Command_CodeRead::execute( vector < string > & argv,
2158 string & out )
2160 if( argv.size() < 1 )
2162 out += "error: insufficient arguments...\n";
2164 else
2166 string code_name;
2167 FILE * read_file;
2169 if( argv.size() >= 2 )
2171 // use second argument as the code_name
2172 code_name = argv[1];
2174 else
2176 // remove the file extension to get the code_name
2177 // or use the whole filename if there is no extension
2178 string::size_type k = argv[0].rfind( "." );
2180 if( k == string::npos )
2181 code_name = argv[1];
2182 else
2183 code_name = string( argv[0], 0, k );
2186 // open the file
2187 read_file = fopen( argv[0].c_str(), "r" );
2188 if( read_file == NULL )
2189 out += "error: unable to open " + argv[0] + " for reading\n";
2191 else
2193 string code = "";
2194 char buffer[256], * result = fgets( buffer, 256, read_file );
2196 if( result == NULL )
2197 out += "error: unable to read " + argv[0] +
2198 ", or file is empty\n";
2200 else
2202 while( result != NULL )
2204 code += buffer;
2205 result = fgets( buffer, 256, read_file );
2208 caller->saved_code[code_name] = code;
2211 fclose( read_file );
2215 if( argv.size() > 2 )
2216 out += "warning: ignoring excess arguments...\n";
2218 return 0;