History

the only constant is change.

Ge Wang committed 9 years ago

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

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

Unified · Split

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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

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

Repository code

Go to file
t