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
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_shell.cpp
29 // author: Spencer Salazar (ssalazar@princeton.edu)
31 //-----------------------------------------------------------------------------
33 #include "chuck_shell.h"
34 #include "chuck_otf.h"
35 #include "util_network.h"
40 #ifndef __PLATFORM_WIN32__
42 #include <sys/param.h>
43 #include <sys/types.h>
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
56 //-----------------------------------------------------------------------------
57 void tokenize_string( string str
, vector
< string
> & tokens
)
60 t_CKINT end_space
= 0;
63 t_CKINT i
= 0, j
= 0, len
= str
.size();
65 for( i
= 0; i
< len
; i
++ )
67 if( isspace( str
[i
] ) && space
)
73 if( isspace( str
[i
] ) && end_space
)
75 tokens
.push_back( string( str
, j
, i
- j
) );
97 else if( str
[i
- 1] == '\\' )
99 str
.erase( i
- 1, 1 );
117 if( str
[i
] == '"' ) //"
132 else if( str
[i
- 1] == '\\' )
134 str
.erase( i
- 1, 1 );
152 if( !squote
&& !dquote
)
159 if( i
> j
&& end_space
)
161 tokens
.push_back( string( str
, j
, i
- j
) );
165 //-----------------------------------------------------------------------------
167 // desc: thread routine
168 //-----------------------------------------------------------------------------
169 void * shell_cb( void * p
)
173 EM_log( CK_LOG_INFO
, "starting thread routine for shell..." );
175 // assuming this is absolutely necessary, an assert may be better
178 shell
= ( Chuck_Shell
* ) p
;
180 //atexit( wait_for_shell );
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..." );
197 //-----------------------------------------------------------------------------
198 // name: Chuck_Shell()
200 //-----------------------------------------------------------------------------
201 Chuck_Shell::Chuck_Shell()
208 code_entry_active
= FALSE
;
211 //-----------------------------------------------------------------------------
212 // name: ~Chuck_Shell()
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
] );
230 //-----------------------------------------------------------------------------
233 //-----------------------------------------------------------------------------
234 t_CKBOOL
Chuck_Shell::init( Chuck_VM
* vm
, Chuck_Shell_UI
* ui
)
237 EM_log( CK_LOG_SYSTEM
, "initializing chuck shell..." );
240 if( initialized
== TRUE
)
242 EM_log( CK_LOG_WARNING
, "chuck shell already initialized" );
249 fprintf( stderr
, "[chuck](via shell): NULL ui passed to Chuck_Shell::init..." );
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..." );
266 vms
.push_back( current_vm
->copy() );
270 code_entry_active
= FALSE
;
273 // init default variables
274 variables
["COMMAND_PROMPT"] = "chuck %> ";
275 variables
["DEFAULT_CONTEXT"] = "shell_global";
278 prompt
= variables
["COMMAND_PROMPT"];
282 // initialize the string -> Chuck_Shell_Command map
283 temp
= new Command_VM();
285 commands
["vm"] = temp
;
286 allocated_commands
.push_back( temp
);
288 temp
= new Command_VMList();
290 commands
["vms"] = temp
;
291 allocated_commands
.push_back( temp
);
293 temp
= new Command_Add();
295 commands
["+"] = temp
;
296 commands
["add"] = temp
;
297 allocated_commands
.push_back( temp
);
299 temp
= new Command_Remove();
301 commands
["-"] = temp
;
302 commands
["remove"] = temp
;
303 allocated_commands
.push_back( temp
);
305 temp
= new Command_Status();
307 commands
["status"] = temp
;
308 commands
["^"] = temp
;
309 allocated_commands
.push_back( temp
);
311 temp
= new Command_Removeall();
313 commands
["removeall"] = temp
;
314 allocated_commands
.push_back( temp
);
316 temp
= new Command_Removelast();
318 commands
["--"] = temp
;
319 allocated_commands
.push_back( temp
);
321 temp
= new Command_Replace();
323 commands
["replace"] = temp
;
324 commands
["="] = temp
;
325 allocated_commands
.push_back( temp
);
327 temp
= new Command_Close();
329 commands
["close"] = temp
;
330 allocated_commands
.push_back( temp
);
332 temp
= new Command_Kill();
334 commands
["kill"] = temp
;
335 allocated_commands
.push_back( temp
);
337 temp
= new Command_Exit();
339 commands
["exit"] = temp
;
340 commands
["quit"] = temp
;
341 allocated_commands
.push_back( temp
);
343 temp
= new Command_Ls();
345 commands
["ls"] = temp
;
346 allocated_commands
.push_back( temp
);
348 temp
= new Command_Pwd();
350 commands
["pwd"] = temp
;
351 allocated_commands
.push_back( temp
);
353 temp
= new Command_Cd();
355 commands
["cd"] = temp
;
356 allocated_commands
.push_back( temp
);
358 temp
= new Command_Alias();
360 commands
["alias"] = temp
;
361 allocated_commands
.push_back( temp
);
363 temp
= new Command_Unalias();
365 commands
["unalias"] = temp
;
366 allocated_commands
.push_back( temp
);
368 temp
= new Command_Source();
370 commands
["source"] = temp
;
371 commands
["."] = temp
;
372 allocated_commands
.push_back( temp
);
374 temp
= new Command_Code();
376 commands
["code"] = temp
;
377 allocated_commands
.push_back( temp
);
385 //-----------------------------------------------------------------------------
388 //-----------------------------------------------------------------------------
389 void Chuck_Shell::run()
392 EM_log( CK_LOG_SYSTEM
, "running chuck shell..." );
395 if(initialized
== FALSE
)
397 fprintf( stderr
, "[chuck](via shell): shell not initialized...\n" );
404 ui
->next_result( "welcome to chuck shell!\n" );
405 // ui->next_result( "(type \"help\" for more information)\n" );
411 if( ui
->next_command( prompt
, command
) == TRUE
)
416 //printf( "chuck_shell::run\n" );
418 // execute the command
419 execute( command
, result
);
424 // pass the result to the shell ui
425 ui
->next_result( result
);
433 EM_log( CK_LOG_SYSTEM
, "exiting chuck shell..." );
436 //-----------------------------------------------------------------------------
439 //-----------------------------------------------------------------------------
440 t_CKBOOL
Chuck_Shell::execute( string
& in
, string
& out
)
448 // vector of string tokens
449 vector
< string
> vec
;
451 // clear the response
454 // first find out if this is code to run
455 if( !code_entry_active
&& in
[in
.find_first_not_of( " \t\v\n" )] == '{' )
458 if( code_entry_active
)
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
);
479 string temp
= "code save " + vec
[0];
480 execute( temp
, out
);
487 // divide the string into white space separated substrings
488 tokenize_string( in
, vec
);
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() );
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";
514 // execute the command
516 Command
* command
= commands
[vec
[0]];
517 vec
.erase( vec
.begin() );
518 if( command
->execute( vec
, out
) == 0 )
528 //-----------------------------------------------------------------------------
529 // name: start_code()
531 //-----------------------------------------------------------------------------
532 void Chuck_Shell::start_code()
535 code_entry_active
= TRUE
;
539 //-----------------------------------------------------------------------------
540 // name: continue_code()
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
550 #ifndef __PLATFORM_WIN32__
551 snprintf( buf
, 16, "code %2d> ", (int)scope
);
553 sprintf( buf
, "code %2d> ", scope
);
558 if( in
.find( "}" ) != string::npos
)
559 // decrease the scope one level and change the prompt
563 #ifndef __PLATFORM_WIN32__
564 snprintf( buf
, 16, "code %2d> ", (int)scope
);
566 sprintf( buf
, "code %2d> ", scope
);
571 // collect this line as ChucK code
575 // the end of this code block -- lets execute it on the current_vm
576 code_entry_active
= FALSE
;
579 //-----------------------------------------------------------------------------
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
);
593 out
+= string( "shell: error: unable to create tmpfile at " ) + tmp_dir
+ "\n";
594 delete[] tmp_filepath
;
595 prompt
= variables
["COMMAND_PROMPT"];
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"];
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"];
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"];
625 // write the code to the temp file
626 fprintf( tmp_file
, "%s", code
.c_str() );
629 string argv
= string( command
) + tmp_filepath
;
631 this->execute( argv
, out
);
632 // if( this->execute( argv, out ) )
636 #ifndef __PLATFORM_WIN32__
637 unlink( tmp_filepath
);
639 DeleteFile( tmp_filepath
);
640 #endif // __PLATFORM_WIN32__
642 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__LINUX_JACK__)
643 delete[] tmp_filepath
;
646 prompt
= variables
["COMMAND_PROMPT"];
649 //-----------------------------------------------------------------------------
650 // name: do_context()
652 //-----------------------------------------------------------------------------
653 void Chuck_Shell::do_code_context( string
& )
658 //-----------------------------------------------------------------------------
661 //-----------------------------------------------------------------------------
662 void Chuck_Shell::close()
668 //-----------------------------------------------------------------------------
671 //-----------------------------------------------------------------------------
672 void Chuck_Shell::exit()
676 if( process_vm
!= NULL
)
680 //-----------------------------------------------------------------------------
683 //-----------------------------------------------------------------------------
684 t_CKBOOL
Chuck_Shell_Network_VM::init( const string
& hostname
, t_CKINT port
)
686 this->hostname
= hostname
;
691 //-----------------------------------------------------------------------------
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
);
702 //-----------------------------------------------------------------------------
705 //-----------------------------------------------------------------------------
706 t_CKBOOL
Chuck_Shell_Network_VM::add_shred( const vector
< string
> & files
,
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 );
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
);
729 /* send the command */
730 if( otf_send_cmd( vec_len
, argv
, i
, hostname
.c_str(), port
) )
734 out
+= "add: error: command failed\n";
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
];
750 //-----------------------------------------------------------------------------
751 // name: remove_shred()
753 //-----------------------------------------------------------------------------
754 t_CKBOOL
Chuck_Shell_Network_VM::remove_shred( const vector
< string
> & ids
,
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 );
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
);
777 /* send the command */
778 if( otf_send_cmd( vec_len
, argv
, i
, hostname
.c_str(), port
) )
782 out
+= "remove: error: command failed\n";
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
];
798 //-----------------------------------------------------------------------------
799 // name: remove_all()
801 //-----------------------------------------------------------------------------
802 t_CKBOOL
Chuck_Shell_Network_VM::remove_all( string
& out
)
804 t_CKBOOL return_val
= TRUE
;
806 const char * argv
= "--removeall";
807 if( !otf_send_cmd( 1, &argv
, j
, hostname
.c_str(), port
) )
809 out
+= "removeall: error: command failed\n";
816 //-----------------------------------------------------------------------------
817 // name: remove_last()
819 //-----------------------------------------------------------------------------
820 t_CKBOOL
Chuck_Shell_Network_VM::remove_last( string
& out
)
822 t_CKBOOL return_val
= TRUE
;
824 const char * argv
= "--";
825 if( !otf_send_cmd( 1, &argv
, j
, hostname
.c_str(), port
) )
827 out
+= "removelast: error: command failed\n";
834 //-----------------------------------------------------------------------------
835 // name: replace_shred()
837 //-----------------------------------------------------------------------------
838 t_CKBOOL
Chuck_Shell_Network_VM::replace_shred( const vector
< string
> &vec
,
843 out
+= "replace: error: insufficient arguments...\n";
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
);
865 /* send the command */
866 if( otf_send_cmd( vec_len
, argv
, i
, hostname
.c_str(), port
) )
871 out
+= "replace: error: command failed\n";
875 if( vec
.size() % 2 != 0 )
877 out
+= "repalce: warning: ignoring excess arguments\n";
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
];
893 //-----------------------------------------------------------------------------
896 //-----------------------------------------------------------------------------
897 t_CKBOOL
Chuck_Shell_Network_VM::status( string
& out
)
899 const char * argv
= "--status";
900 t_CKBOOL return_val
= FALSE
;
903 if( otf_send_cmd( 1, &argv
, j
, hostname
.c_str(), port
) )
908 out
+= "status: error: command failed\n";
914 //-----------------------------------------------------------------------------
917 //-----------------------------------------------------------------------------
918 t_CKBOOL
Chuck_Shell_Network_VM::kill( string
& out
)
920 const char * argv
= "--kill";
924 if( otf_send_cmd( 1, &argv
, j
, hostname
.c_str(), port
) )
930 out
+= "kill: error: command failed";
936 //-----------------------------------------------------------------------------
938 // desc: returns a somewhat descriptive full name for this VM
939 //-----------------------------------------------------------------------------
940 string
Chuck_Shell_Network_VM::fullname()
943 sprintf( buf
, ":%u", (int)port
);
945 return hostname
+ buf
;
948 //-----------------------------------------------------------------------------
951 //-----------------------------------------------------------------------------
952 t_CKBOOL
Chuck_Shell_UI::init()
957 //-----------------------------------------------------------------------------
960 //-----------------------------------------------------------------------------
961 t_CKBOOL
Chuck_Shell::Command::init( Chuck_Shell
* caller
)
963 this->caller
= caller
;
967 //-----------------------------------------------------------------------------
970 //-----------------------------------------------------------------------------
971 string
Chuck_Shell::Command::usage()
973 return "no usage specified";
976 //-----------------------------------------------------------------------------
977 // name: long_usage()
979 //-----------------------------------------------------------------------------
980 string
Chuck_Shell::Command::long_usage()
982 return "no usage specified";
985 //-----------------------------------------------------------------------------
988 //-----------------------------------------------------------------------------
989 t_CKINT
Chuck_Shell::Command_Add::execute( vector
< string
> & argv
,
994 if( caller
->current_vm
== NULL
)
996 out
+= "add: error: not attached to a VM\n";
1000 else if( argv
.size() < 1 )
1002 out
+= "usage: " + usage() + "\n";
1008 result
= caller
->current_vm
->add_shred( argv
, out
);
1014 //-----------------------------------------------------------------------------
1017 //-----------------------------------------------------------------------------
1018 string
Chuck_Shell::Command_Add::usage()
1020 return "add file ...";
1023 //-----------------------------------------------------------------------------
1026 //-----------------------------------------------------------------------------
1027 t_CKINT
Chuck_Shell::Command_Remove::execute( vector
< string
> & argv
,
1032 if( caller
->current_vm
== NULL
)
1034 out
+= "remove: error: not attached to a VM\n";
1038 else if( argv
.size() < 1 )
1040 out
+= "usage: " + usage() + "\n";
1045 result
= caller
->current_vm
->remove_shred( argv
, out
);
1050 //-----------------------------------------------------------------------------
1053 //-----------------------------------------------------------------------------
1054 string
Chuck_Shell::Command_Remove::usage()
1056 return "remove shred_number ...";
1059 //-----------------------------------------------------------------------------
1062 //-----------------------------------------------------------------------------
1063 t_CKINT
Chuck_Shell::Command_Removeall::execute( vector
< string
> & argv
,
1068 if( caller
->current_vm
== NULL
)
1070 out
+= "removeall: error: not attached to a VM\n";
1074 else if( argv
.size() > 0 )
1076 out
+= "usage " + usage() + "\n";
1081 result
= caller
->current_vm
->remove_all( out
);
1086 //-----------------------------------------------------------------------------
1089 //-----------------------------------------------------------------------------
1090 string
Chuck_Shell::Command_Removeall::usage()
1095 //-----------------------------------------------------------------------------
1098 //-----------------------------------------------------------------------------
1099 t_CKINT
Chuck_Shell::Command_Removelast::execute( vector
< string
> & argv
,
1102 t_CKINT result
= -1;
1104 if( caller
->current_vm
== NULL
)
1105 out
+= "removelast: error: not attached to a VM\n";
1107 result
= caller
->current_vm
->remove_last( out
);
1109 if( argv
.size() > 0 )
1110 out
+= "removelast: warning: ignoring excess arguments...\n";
1115 //-----------------------------------------------------------------------------
1118 //-----------------------------------------------------------------------------
1119 string
Chuck_Shell::Command_Removelast::usage()
1121 return "removelast";
1124 //-----------------------------------------------------------------------------
1127 //-----------------------------------------------------------------------------
1128 t_CKINT
Chuck_Shell::Command_Replace::execute( vector
< string
> & argv
,
1131 if( caller
->current_vm
== NULL
)
1133 out
+= "replace: error: not attached to a VM\n";
1137 caller
->current_vm
->replace_shred( argv
, out
);
1142 //-----------------------------------------------------------------------------
1145 //-----------------------------------------------------------------------------
1146 string
Chuck_Shell::Command_Replace::usage()
1148 return "replace shred_id file ...";
1151 //-----------------------------------------------------------------------------
1154 //-----------------------------------------------------------------------------
1155 t_CKINT
Chuck_Shell::Command_Status::execute( vector
< string
> & argv
,
1160 if( caller
->current_vm
== NULL
)
1162 out
+= "status: error: not attached to a VM\n";
1166 else if( argv
.size() > 0 )
1168 out
+= "usage: " + usage() + "\n";
1173 result
= caller
->current_vm
->status( out
);
1178 //-----------------------------------------------------------------------------
1181 //-----------------------------------------------------------------------------
1182 string
Chuck_Shell::Command_Status::usage()
1187 //-----------------------------------------------------------------------------
1190 //-----------------------------------------------------------------------------
1191 t_CKINT
Chuck_Shell::Command_Kill::execute( vector
< string
> & argv
,
1194 caller
->current_vm
->kill( out
);
1195 if( argv
.size() > 0 )
1196 out
+= "kill: warning: ignoring excess arguments...\n";
1201 //-----------------------------------------------------------------------------
1204 //-----------------------------------------------------------------------------
1205 t_CKINT
Chuck_Shell::Command_Close::execute( vector
< string
> & argv
,
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";
1221 //-----------------------------------------------------------------------------
1224 //-----------------------------------------------------------------------------
1225 t_CKINT
Chuck_Shell::Command_Exit::execute( vector
< string
> & argv
,
1229 if( argv
.size() > 0 )
1230 out
+= "exit: warning: ignoring excess arguments...\n";
1235 //-----------------------------------------------------------------------------
1238 //-----------------------------------------------------------------------------
1239 t_CKINT
Chuck_Shell::Command_Ls::execute( vector
< string
> & argv
,
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";
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
);
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";
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
)
1291 closedir( dir_handle
);
1296 if( argv
.size() == 0 )
1299 LPTSTR cwd
= new char [k
];
1300 WIN32_FIND_DATA find_data
;
1302 i
= GetCurrentDirectory( k
- 2, cwd
);
1306 SAFE_DELETE_ARRAY( cwd
);
1307 cwd
= new char [i
+ 2];
1308 GetCurrentDirectory( i
, cwd
);
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
);
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
);
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
)
1353 FindClose( find_handle
);
1358 #endif // __PLATFORM_WIN32__
1362 //-----------------------------------------------------------------------------
1365 //-----------------------------------------------------------------------------
1366 t_CKINT
Chuck_Shell::Command_Cd::execute( vector
< string
> & argv
,
1369 #ifndef __PLATFORM_WIN32__
1370 if( argv
.size() < 1 )
1372 if( chdir( getenv( "HOME" ) ) )
1373 out
+= "cd: error: command failed\n";
1378 if( chdir( argv
[0].c_str() ) )
1379 out
+= "cd: error: command failed\n";
1383 if( argv
.size() < 1 )
1384 out
+= "usage: " + usage() + "\n";
1388 if( !SetCurrentDirectory( argv
[0].c_str() ) )
1389 out
+= "cd: error: command failed\n";
1392 #endif //__PLATFORM_WIN32__
1396 //-----------------------------------------------------------------------------
1399 //-----------------------------------------------------------------------------
1400 t_CKINT
Chuck_Shell::Command_Pwd::execute( vector
< string
> & argv
,
1403 #ifndef __PLATFORM_WIN32__
1404 char * cwd
= getcwd( NULL
, 0 );
1405 out
+= string( cwd
) + "\n";
1409 LPTSTR cwd
= new char [k
];
1410 i
= GetCurrentDirectory( k
, cwd
);
1414 SAFE_DELETE_ARRAY( cwd
);
1416 GetCurrentDirectory( i
, cwd
);
1419 out
+= string( cwd
) + "\n";
1421 SAFE_DELETE_ARRAY( cwd
);
1424 if( argv
.size() > 0 )
1425 out
+= "pwd: warning: ignoring excess arguments...\n";
1430 //-----------------------------------------------------------------------------
1433 //-----------------------------------------------------------------------------
1434 t_CKINT
Chuck_Shell::Command_Alias::execute( vector
< string
> & argv
,
1437 vector
<string
>::size_type i
, len
= argv
.size();
1438 string::size_type j
;
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";
1452 out
+= "alias " + argv
[i
] + "='" +
1453 caller
->aliases
[argv
[i
]] + "'\n";
1458 a
= string( argv
[i
], 0, j
);
1459 b
= string( argv
[i
], j
+ 1, string::npos
);
1460 caller
->aliases
[a
] = b
;
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";
1476 //-----------------------------------------------------------------------------
1479 //-----------------------------------------------------------------------------
1480 t_CKINT
Chuck_Shell::Command_Unalias::execute( vector
< string
> & argv
,
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";
1491 caller
->aliases
.erase( argv
[i
] );
1497 //-----------------------------------------------------------------------------
1500 //-----------------------------------------------------------------------------
1501 t_CKINT
Chuck_Shell::Command_Source::execute( vector
< string
> & argv
,
1504 vector
<string
>::size_type i
, len
= argv
.size();
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
];
1517 while( fgets( line_buf
, 255, source_file
) != NULL
)
1519 line
= string( line_buf
);
1520 caller
->execute( line
, temp
);
1529 //-----------------------------------------------------------------------------
1532 //-----------------------------------------------------------------------------
1533 t_CKINT
Chuck_Shell::Command_Help::execute( vector
< string
> & argv
,
1540 //-----------------------------------------------------------------------------
1543 //-----------------------------------------------------------------------------
1544 t_CKBOOL
Chuck_Shell::Command_VM::init( Chuck_Shell
* caller
)
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
);
1588 //-----------------------------------------------------------------------------
1589 // name: ~Command_VM()
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 //-----------------------------------------------------------------------------
1604 //-----------------------------------------------------------------------------
1605 t_CKINT
Chuck_Shell::Command_VM::execute( vector
< string
> & argv
,
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";
1616 // call the mapped command
1618 Command
* command
= commands
[argv
[0]];
1619 argv
.erase( argv
.begin() );
1620 command
->execute( argv
, out
);
1626 //-----------------------------------------------------------------------------
1629 //-----------------------------------------------------------------------------
1630 string
Chuck_Shell::Command_VM::usage()
1632 return "vm [command] [args] ...";
1635 //-----------------------------------------------------------------------------
1638 //-----------------------------------------------------------------------------
1639 t_CKINT
Chuck_Shell::Command_VMAttach::execute( vector
< string
> & argv
,
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";
1657 string::size_type i
= argv
[0].find( ":" );
1659 if( i
== string::npos
)
1660 // couldn't find a port number; use the default
1669 port
= strtol( argv
[0].c_str() + i
+ 1, NULL
, 10 );
1671 out
+= string( "error: invalid port '" ) +
1672 string( argv
[0].c_str() + i
+ 1 ) + "'\n";
1675 hostname
= string( argv
[0], 0, i
);
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 );
1692 SAFE_DELETE( caller
->current_vm
);
1693 caller
->current_vm
= new_vm
;
1694 out
+= argv
[0] + " is now current VM\n";
1700 out
+= "error: unable to attach to " + argv
[0] + "\n";
1704 if( argv
.size() > 1 )
1705 out
+= "warning: ignoring excess arguments...\n";
1710 //-----------------------------------------------------------------------------
1713 //-----------------------------------------------------------------------------
1714 t_CKINT
Chuck_Shell::Command_VMAdd::execute( vector
< string
> & argv
,
1719 if( caller
->current_vm
== NULL
)
1721 out
+= "error: no VM to save\n";
1725 caller
->vms
.push_back( caller
->current_vm
->copy() );
1727 #ifndef __PLATFORM_WIN32__
1728 snprintf( buf
, 16, "%u", caller
->vms
.size() - 1 );
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";
1741 //-----------------------------------------------------------------------------
1744 //-----------------------------------------------------------------------------
1745 t_CKINT
Chuck_Shell::Command_VMRemove::execute( vector
< string
> & argv
,
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";
1760 SAFE_DELETE( caller
->vms
[vm_no
] );
1767 //-----------------------------------------------------------------------------
1770 //-----------------------------------------------------------------------------
1771 t_CKINT
Chuck_Shell::Command_VMSwap::execute( vector
< string
> & argv
,
1774 vector
<string
>::size_type new_vm
= 0;
1776 if( argv
.size() < 1 )
1778 out
+= string( "error: too few arguments...\n" );
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";
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";
1800 //-----------------------------------------------------------------------------
1803 //-----------------------------------------------------------------------------
1804 t_CKINT
Chuck_Shell::Command_VMList::execute( vector
< string
> & argv
,
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
);
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";
1833 //-----------------------------------------------------------------------------
1836 //-----------------------------------------------------------------------------
1837 t_CKINT
Chuck_Shell::Command_VMAttachAdd::execute( vector
< string
> & argv
,
1841 string exec
= string( "vm @ " ) + ( argv
.size() > 0 ? argv
[0] : "" );
1843 if( caller
->execute( exec
, out
) )
1846 if( caller
->execute( exec
, out
) )
1859 //-----------------------------------------------------------------------------
1862 //-----------------------------------------------------------------------------
1863 t_CKBOOL
Chuck_Shell::Command_Code::init( Chuck_Shell
* caller
)
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
);
1908 //-----------------------------------------------------------------------------
1909 // name: ~Command_Code()
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 //-----------------------------------------------------------------------------
1924 //-----------------------------------------------------------------------------
1925 t_CKINT
Chuck_Shell::Command_Code::execute( vector
< string
> & argv
,
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";
1937 // call the mapped command
1938 Command
* command
= commands
[argv
[0]];
1939 argv
.erase( argv
.begin() );
1940 command
->execute( argv
, out
);
1946 //-----------------------------------------------------------------------------
1949 //-----------------------------------------------------------------------------
1950 string
Chuck_Shell::Command_Code::usage()
1952 return "code [command] [args] ...";
1955 //-----------------------------------------------------------------------------
1958 //-----------------------------------------------------------------------------
1959 t_CKINT
Chuck_Shell::Command_CodeSave::execute( vector
< string
> & argv
,
1962 if( argv
.size() < 1 )
1964 out
+= "error: please specify a name to identify the code\n";
1968 if( caller
->code
== "" )
1969 out
+= "error: no code to save\n";
1972 caller
->saved_code
[argv
[0]] = caller
->code
;
1974 if( argv
.size() > 1 )
1975 out
+= "warning: ignoring excess arguments...\n";
1981 //-----------------------------------------------------------------------------
1984 //-----------------------------------------------------------------------------
1985 t_CKINT
Chuck_Shell::Command_CodeList::execute( vector
< string
> & argv
,
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";
1999 //-----------------------------------------------------------------------------
2002 //-----------------------------------------------------------------------------
2003 t_CKINT
Chuck_Shell::Command_CodeAdd::execute( vector
< string
> & argv
,
2006 if( argv
.size() == 0 )
2008 if( caller
->code
!= "" )
2009 caller
->do_code( caller
->code
, out
);
2012 out
+= "error: no code to add\n";
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";
2026 caller
->do_code( caller
->code
, out
);
2033 //-----------------------------------------------------------------------------
2036 //-----------------------------------------------------------------------------
2037 t_CKINT
Chuck_Shell::Command_CodePrint::execute( vector
< string
> & argv
,
2040 if( argv
.size() == 0 )
2042 if( caller
->code
!= "" )
2043 out
+= caller
->code
+ "\n";
2045 out
+= "error: no code to print\n";
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";
2060 string code
= caller
->saved_code
[argv
[i
]];
2062 out
+= argv
[i
] + ":\n";
2071 //-----------------------------------------------------------------------------
2074 //-----------------------------------------------------------------------------
2075 t_CKINT
Chuck_Shell::Command_CodeDelete::execute( vector
< string
> & argv
,
2078 if( argv
.size() == 0 )
2080 out
+= "error: specify the code to delete\n";
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";
2093 caller
->saved_code
.erase( argv
[i
] );
2101 //-----------------------------------------------------------------------------
2104 //-----------------------------------------------------------------------------
2105 t_CKINT
Chuck_Shell::Command_CodeWrite::execute( vector
< string
> & argv
,
2108 if( argv
.size() < 1 )
2110 out
+= "error: insufficient arguments...\n";
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";
2122 string code
= caller
->saved_code
[argv
[0]];
2125 if( argv
.size() >= 2 )
2127 // use second argument as filename
2132 // append .ck to the code name to get the file name
2133 filename
= argv
[0] + ".ck";
2137 write_file
= fopen( filename
.c_str(), "w" );
2139 if( write_file
== NULL
)
2141 out
+= "error: unable to open " + filename
+ " for writing\n";
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";
2160 //-----------------------------------------------------------------------------
2163 //-----------------------------------------------------------------------------
2164 t_CKINT
Chuck_Shell::Command_CodeRead::execute( vector
< string
> & argv
,
2167 if( argv
.size() < 1 )
2169 out
+= "error: insufficient arguments...\n";
2176 if( argv
.size() >= 2 )
2178 // use second argument as the code_name
2179 code_name
= argv
[1];
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];
2190 code_name
= string( argv
[0], 0, k
);
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";
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";
2209 while( result
!= NULL
)
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";