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 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
) )
732 out
+= "add: error: command failed\n";
736 /* clean up heap data */
737 for( j
= 0; j
< vec_len
; j
++ )
744 //-----------------------------------------------------------------------------
745 // name: remove_shred()
747 //-----------------------------------------------------------------------------
748 t_CKBOOL
Chuck_Shell_Network_VM::remove_shred( const vector
< string
> & ids
,
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
) )
774 out
+= "remove: error: command failed\n";
778 /* clean up heap data */
779 for( j
= 0; j
< vec_len
; j
++ )
786 //-----------------------------------------------------------------------------
787 // name: remove_all()
789 //-----------------------------------------------------------------------------
790 t_CKBOOL
Chuck_Shell_Network_VM::remove_all( string
& out
)
792 t_CKBOOL return_val
= TRUE
;
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";
805 //-----------------------------------------------------------------------------
806 // name: remove_last()
808 //-----------------------------------------------------------------------------
809 t_CKBOOL
Chuck_Shell_Network_VM::remove_last( string
& out
)
811 t_CKBOOL return_val
= TRUE
;
813 char ** argv
= new char *;
815 if( !otf_send_cmd( 1, argv
, j
, hostname
.c_str(), port
) )
817 out
+= "removelast: error: command failed\n";
824 //-----------------------------------------------------------------------------
825 // name: replace_shred()
827 //-----------------------------------------------------------------------------
828 t_CKBOOL
Chuck_Shell_Network_VM::replace_shred( const vector
< string
> &vec
,
833 out
+= "replace: error: insufficient arguments...\n";
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
) )
860 out
+= "replace: error: command failed\n";
864 if( vec
.size() % 2 != 0 )
866 out
+= "repalce: warning: ignoring excess arguments\n";
870 /* clean up heap data */
871 for( j
= 1; j
< vec_len
; j
++ )
878 //-----------------------------------------------------------------------------
881 //-----------------------------------------------------------------------------
882 t_CKBOOL
Chuck_Shell_Network_VM::status( string
& out
)
884 char ** argv
= new char *;
885 t_CKBOOL return_val
= FALSE
;
888 argv
[0] = "--status";
889 if( otf_send_cmd( 1, argv
, j
, hostname
.c_str(), port
) )
895 out
+= "status: error: command failed\n";
903 //-----------------------------------------------------------------------------
906 //-----------------------------------------------------------------------------
907 t_CKBOOL
Chuck_Shell_Network_VM::kill( string
& out
)
909 char ** argv
= new char *;
915 if( otf_send_cmd( 1, argv
, j
, hostname
.c_str(), port
) )
921 out
+= "kill: error: command failed";
929 //-----------------------------------------------------------------------------
931 // desc: returns a somewhat descriptive full name for this VM
932 //-----------------------------------------------------------------------------
933 string
Chuck_Shell_Network_VM::fullname()
936 sprintf( buf
, ":%u", (int)port
);
938 return hostname
+ buf
;
941 //-----------------------------------------------------------------------------
944 //-----------------------------------------------------------------------------
945 t_CKBOOL
Chuck_Shell_UI::init()
950 //-----------------------------------------------------------------------------
953 //-----------------------------------------------------------------------------
954 t_CKBOOL
Chuck_Shell::Command::init( Chuck_Shell
* caller
)
956 this->caller
= caller
;
960 //-----------------------------------------------------------------------------
963 //-----------------------------------------------------------------------------
964 string
Chuck_Shell::Command::usage()
966 return "no usage specified";
969 //-----------------------------------------------------------------------------
970 // name: long_usage()
972 //-----------------------------------------------------------------------------
973 string
Chuck_Shell::Command::long_usage()
975 return "no usage specified";
978 //-----------------------------------------------------------------------------
981 //-----------------------------------------------------------------------------
982 t_CKINT
Chuck_Shell::Command_Add::execute( vector
< string
> & argv
,
987 if( caller
->current_vm
== NULL
)
989 out
+= "add: error: not attached to a VM\n";
993 else if( argv
.size() < 1 )
995 out
+= "usage: " + usage() + "\n";
1001 result
= caller
->current_vm
->add_shred( argv
, out
);
1007 //-----------------------------------------------------------------------------
1010 //-----------------------------------------------------------------------------
1011 string
Chuck_Shell::Command_Add::usage()
1013 return "add file ...";
1016 //-----------------------------------------------------------------------------
1019 //-----------------------------------------------------------------------------
1020 t_CKINT
Chuck_Shell::Command_Remove::execute( vector
< string
> & argv
,
1025 if( caller
->current_vm
== NULL
)
1027 out
+= "remove: error: not attached to a VM\n";
1031 else if( argv
.size() < 1 )
1033 out
+= "usage: " + usage() + "\n";
1038 result
= caller
->current_vm
->remove_shred( argv
, out
);
1043 //-----------------------------------------------------------------------------
1046 //-----------------------------------------------------------------------------
1047 string
Chuck_Shell::Command_Remove::usage()
1049 return "remove shred_number ...";
1052 //-----------------------------------------------------------------------------
1055 //-----------------------------------------------------------------------------
1056 t_CKINT
Chuck_Shell::Command_Removeall::execute( vector
< string
> & argv
,
1061 if( caller
->current_vm
== NULL
)
1063 out
+= "removeall: error: not attached to a VM\n";
1067 else if( argv
.size() > 0 )
1069 out
+= "usage " + usage() + "\n";
1074 result
= caller
->current_vm
->remove_all( out
);
1079 //-----------------------------------------------------------------------------
1082 //-----------------------------------------------------------------------------
1083 string
Chuck_Shell::Command_Removeall::usage()
1088 //-----------------------------------------------------------------------------
1091 //-----------------------------------------------------------------------------
1092 t_CKINT
Chuck_Shell::Command_Removelast::execute( vector
< string
> & argv
,
1095 t_CKINT result
= -1;
1097 if( caller
->current_vm
== NULL
)
1098 out
+= "removelast: error: not attached to a VM\n";
1100 result
= caller
->current_vm
->remove_last( out
);
1102 if( argv
.size() > 0 )
1103 out
+= "removelast: warning: ignoring excess arguments...\n";
1108 //-----------------------------------------------------------------------------
1111 //-----------------------------------------------------------------------------
1112 string
Chuck_Shell::Command_Removelast::usage()
1114 return "removelast";
1117 //-----------------------------------------------------------------------------
1120 //-----------------------------------------------------------------------------
1121 t_CKINT
Chuck_Shell::Command_Replace::execute( vector
< string
> & argv
,
1124 if( caller
->current_vm
== NULL
)
1126 out
+= "replace: error: not attached to a VM\n";
1130 caller
->current_vm
->replace_shred( argv
, out
);
1135 //-----------------------------------------------------------------------------
1138 //-----------------------------------------------------------------------------
1139 string
Chuck_Shell::Command_Replace::usage()
1141 return "replace shred_id file ...";
1144 //-----------------------------------------------------------------------------
1147 //-----------------------------------------------------------------------------
1148 t_CKINT
Chuck_Shell::Command_Status::execute( vector
< string
> & argv
,
1153 if( caller
->current_vm
== NULL
)
1155 out
+= "status: error: not attached to a VM\n";
1159 else if( argv
.size() > 0 )
1161 out
+= "usage: " + usage() + "\n";
1166 result
= caller
->current_vm
->status( out
);
1171 //-----------------------------------------------------------------------------
1174 //-----------------------------------------------------------------------------
1175 string
Chuck_Shell::Command_Status::usage()
1180 //-----------------------------------------------------------------------------
1183 //-----------------------------------------------------------------------------
1184 t_CKINT
Chuck_Shell::Command_Kill::execute( vector
< string
> & argv
,
1187 caller
->current_vm
->kill( out
);
1188 if( argv
.size() > 0 )
1189 out
+= "kill: warning: ignoring excess arguments...\n";
1194 //-----------------------------------------------------------------------------
1197 //-----------------------------------------------------------------------------
1198 t_CKINT
Chuck_Shell::Command_Close::execute( vector
< string
> & argv
,
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";
1214 //-----------------------------------------------------------------------------
1217 //-----------------------------------------------------------------------------
1218 t_CKINT
Chuck_Shell::Command_Exit::execute( vector
< string
> & argv
,
1222 if( argv
.size() > 0 )
1223 out
+= "exit: warning: ignoring excess arguments...\n";
1228 //-----------------------------------------------------------------------------
1231 //-----------------------------------------------------------------------------
1232 t_CKINT
Chuck_Shell::Command_Ls::execute( vector
< string
> & argv
,
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";
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
);
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";
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
)
1284 closedir( dir_handle
);
1289 if( argv
.size() == 0 )
1292 LPTSTR cwd
= new char [k
];
1293 WIN32_FIND_DATA find_data
;
1295 i
= GetCurrentDirectory( k
- 2, cwd
);
1299 SAFE_DELETE_ARRAY( cwd
);
1300 cwd
= new char [i
+ 2];
1301 GetCurrentDirectory( i
, cwd
);
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
);
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
);
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
)
1346 FindClose( find_handle
);
1351 #endif // __PLATFORM_WIN32__
1355 //-----------------------------------------------------------------------------
1358 //-----------------------------------------------------------------------------
1359 t_CKINT
Chuck_Shell::Command_Cd::execute( vector
< string
> & argv
,
1362 #ifndef __PLATFORM_WIN32__
1363 if( argv
.size() < 1 )
1365 if( chdir( getenv( "HOME" ) ) )
1366 out
+= "cd: error: command failed\n";
1371 if( chdir( argv
[0].c_str() ) )
1372 out
+= "cd: error: command failed\n";
1376 if( argv
.size() < 1 )
1377 out
+= "usage: " + usage() + "\n";
1381 if( !SetCurrentDirectory( argv
[0].c_str() ) )
1382 out
+= "cd: error: command failed\n";
1385 #endif //__PLATFORM_WIN32__
1389 //-----------------------------------------------------------------------------
1392 //-----------------------------------------------------------------------------
1393 t_CKINT
Chuck_Shell::Command_Pwd::execute( vector
< string
> & argv
,
1396 #ifndef __PLATFORM_WIN32__
1397 char * cwd
= getcwd( NULL
, 0 );
1398 out
+= string( cwd
) + "\n";
1402 LPTSTR cwd
= new char [k
];
1403 i
= GetCurrentDirectory( k
, cwd
);
1407 SAFE_DELETE_ARRAY( cwd
);
1409 GetCurrentDirectory( i
, cwd
);
1412 out
+= string( cwd
) + "\n";
1414 SAFE_DELETE_ARRAY( cwd
);
1417 if( argv
.size() > 0 )
1418 out
+= "pwd: warning: ignoring excess arguments...\n";
1423 //-----------------------------------------------------------------------------
1426 //-----------------------------------------------------------------------------
1427 t_CKINT
Chuck_Shell::Command_Alias::execute( vector
< string
> & argv
,
1430 vector
<string
>::size_type i
, len
= argv
.size();
1431 string::size_type j
;
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";
1445 out
+= "alias " + argv
[i
] + "='" +
1446 caller
->aliases
[argv
[i
]] + "'\n";
1451 a
= string( argv
[i
], 0, j
);
1452 b
= string( argv
[i
], j
+ 1, string::npos
);
1453 caller
->aliases
[a
] = b
;
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";
1469 //-----------------------------------------------------------------------------
1472 //-----------------------------------------------------------------------------
1473 t_CKINT
Chuck_Shell::Command_Unalias::execute( vector
< string
> & argv
,
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";
1484 caller
->aliases
.erase( argv
[i
] );
1490 //-----------------------------------------------------------------------------
1493 //-----------------------------------------------------------------------------
1494 t_CKINT
Chuck_Shell::Command_Source::execute( vector
< string
> & argv
,
1497 vector
<string
>::size_type i
, len
= argv
.size();
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
];
1510 while( fgets( line_buf
, 255, source_file
) != NULL
)
1512 line
= string( line_buf
);
1513 caller
->execute( line
, temp
);
1522 //-----------------------------------------------------------------------------
1525 //-----------------------------------------------------------------------------
1526 t_CKINT
Chuck_Shell::Command_Help::execute( vector
< string
> & argv
,
1533 //-----------------------------------------------------------------------------
1536 //-----------------------------------------------------------------------------
1537 t_CKBOOL
Chuck_Shell::Command_VM::init( Chuck_Shell
* caller
)
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
);
1581 //-----------------------------------------------------------------------------
1582 // name: ~Command_VM()
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 //-----------------------------------------------------------------------------
1597 //-----------------------------------------------------------------------------
1598 t_CKINT
Chuck_Shell::Command_VM::execute( vector
< string
> & argv
,
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";
1609 // call the mapped command
1611 Command
* command
= commands
[argv
[0]];
1612 argv
.erase( argv
.begin() );
1613 command
->execute( argv
, out
);
1619 //-----------------------------------------------------------------------------
1622 //-----------------------------------------------------------------------------
1623 string
Chuck_Shell::Command_VM::usage()
1625 return "vm [command] [args] ...";
1628 //-----------------------------------------------------------------------------
1631 //-----------------------------------------------------------------------------
1632 t_CKINT
Chuck_Shell::Command_VMAttach::execute( vector
< string
> & argv
,
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";
1650 string::size_type i
= argv
[0].find( ":" );
1652 if( i
== string::npos
)
1653 // couldn't find a port number; use the default
1662 port
= strtol( argv
[0].c_str() + i
+ 1, NULL
, 10 );
1664 out
+= string( "error: invalid port '" ) +
1665 string( argv
[0].c_str() + i
+ 1 ) + "'\n";
1668 hostname
= string( argv
[0], 0, i
);
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 );
1685 SAFE_DELETE( caller
->current_vm
);
1686 caller
->current_vm
= new_vm
;
1687 out
+= argv
[0] + " is now current VM\n";
1693 out
+= "error: unable to attach to " + argv
[0] + "\n";
1697 if( argv
.size() > 1 )
1698 out
+= "warning: ignoring excess arguments...\n";
1703 //-----------------------------------------------------------------------------
1706 //-----------------------------------------------------------------------------
1707 t_CKINT
Chuck_Shell::Command_VMAdd::execute( vector
< string
> & argv
,
1712 if( caller
->current_vm
== NULL
)
1714 out
+= "error: no VM to save\n";
1718 caller
->vms
.push_back( caller
->current_vm
->copy() );
1720 #ifndef __PLATFORM_WIN32__
1721 snprintf( buf
, 16, "%u", caller
->vms
.size() - 1 );
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";
1734 //-----------------------------------------------------------------------------
1737 //-----------------------------------------------------------------------------
1738 t_CKINT
Chuck_Shell::Command_VMRemove::execute( vector
< string
> & argv
,
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";
1753 SAFE_DELETE( caller
->vms
[vm_no
] );
1760 //-----------------------------------------------------------------------------
1763 //-----------------------------------------------------------------------------
1764 t_CKINT
Chuck_Shell::Command_VMSwap::execute( vector
< string
> & argv
,
1767 vector
<string
>::size_type new_vm
= 0;
1769 if( argv
.size() < 1 )
1771 out
+= string( "error: too few arguments...\n" );
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";
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";
1793 //-----------------------------------------------------------------------------
1796 //-----------------------------------------------------------------------------
1797 t_CKINT
Chuck_Shell::Command_VMList::execute( vector
< string
> & argv
,
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
);
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";
1826 //-----------------------------------------------------------------------------
1829 //-----------------------------------------------------------------------------
1830 t_CKINT
Chuck_Shell::Command_VMAttachAdd::execute( vector
< string
> & argv
,
1834 string exec
= string( "vm @ " ) + ( argv
.size() > 0 ? argv
[0] : "" );
1836 if( caller
->execute( exec
, out
) )
1839 if( caller
->execute( exec
, out
) )
1852 //-----------------------------------------------------------------------------
1855 //-----------------------------------------------------------------------------
1856 t_CKBOOL
Chuck_Shell::Command_Code::init( Chuck_Shell
* caller
)
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
);
1901 //-----------------------------------------------------------------------------
1902 // name: ~Command_Code()
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 //-----------------------------------------------------------------------------
1917 //-----------------------------------------------------------------------------
1918 t_CKINT
Chuck_Shell::Command_Code::execute( vector
< string
> & argv
,
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";
1930 // call the mapped command
1931 Command
* command
= commands
[argv
[0]];
1932 argv
.erase( argv
.begin() );
1933 command
->execute( argv
, out
);
1939 //-----------------------------------------------------------------------------
1942 //-----------------------------------------------------------------------------
1943 string
Chuck_Shell::Command_Code::usage()
1945 return "code [command] [args] ...";
1948 //-----------------------------------------------------------------------------
1951 //-----------------------------------------------------------------------------
1952 t_CKINT
Chuck_Shell::Command_CodeSave::execute( vector
< string
> & argv
,
1955 if( argv
.size() < 1 )
1957 out
+= "error: please specify a name to identify the code\n";
1961 if( caller
->code
== "" )
1962 out
+= "error: no code to save\n";
1965 caller
->saved_code
[argv
[0]] = caller
->code
;
1967 if( argv
.size() > 1 )
1968 out
+= "warning: ignoring excess arguments...\n";
1974 //-----------------------------------------------------------------------------
1977 //-----------------------------------------------------------------------------
1978 t_CKINT
Chuck_Shell::Command_CodeList::execute( vector
< string
> & argv
,
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";
1992 //-----------------------------------------------------------------------------
1995 //-----------------------------------------------------------------------------
1996 t_CKINT
Chuck_Shell::Command_CodeAdd::execute( vector
< string
> & argv
,
1999 if( argv
.size() == 0 )
2001 if( caller
->code
!= "" )
2002 caller
->do_code( caller
->code
, out
);
2005 out
+= "error: no code to add\n";
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";
2019 caller
->do_code( caller
->code
, out
);
2026 //-----------------------------------------------------------------------------
2029 //-----------------------------------------------------------------------------
2030 t_CKINT
Chuck_Shell::Command_CodePrint::execute( vector
< string
> & argv
,
2033 if( argv
.size() == 0 )
2035 if( caller
->code
!= "" )
2036 out
+= caller
->code
+ "\n";
2038 out
+= "error: no code to print\n";
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";
2053 string code
= caller
->saved_code
[argv
[i
]];
2055 out
+= argv
[i
] + ":\n";
2064 //-----------------------------------------------------------------------------
2067 //-----------------------------------------------------------------------------
2068 t_CKINT
Chuck_Shell::Command_CodeDelete::execute( vector
< string
> & argv
,
2071 if( argv
.size() == 0 )
2073 out
+= "error: specify the code to delete\n";
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";
2086 caller
->saved_code
.erase( argv
[i
] );
2094 //-----------------------------------------------------------------------------
2097 //-----------------------------------------------------------------------------
2098 t_CKINT
Chuck_Shell::Command_CodeWrite::execute( vector
< string
> & argv
,
2101 if( argv
.size() < 1 )
2103 out
+= "error: insufficient arguments...\n";
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";
2115 string code
= caller
->saved_code
[argv
[0]];
2118 if( argv
.size() >= 2 )
2120 // use second argument as filename
2125 // append .ck to the code name to get the file name
2126 filename
= argv
[0] + ".ck";
2130 write_file
= fopen( filename
.c_str(), "w" );
2132 if( write_file
== NULL
)
2134 out
+= "error: unable to open " + filename
+ " for writing\n";
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";
2153 //-----------------------------------------------------------------------------
2156 //-----------------------------------------------------------------------------
2157 t_CKINT
Chuck_Shell::Command_CodeRead::execute( vector
< string
> & argv
,
2160 if( argv
.size() < 1 )
2162 out
+= "error: insufficient arguments...\n";
2169 if( argv
.size() >= 2 )
2171 // use second argument as the code_name
2172 code_name
= argv
[1];
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];
2183 code_name
= string( argv
[0], 0, k
);
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";
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";
2202 while( result
!= NULL
)
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";