/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// file: chuck_shell.cpp// desc: chuck shell implementation//// author: Spencer Salazar (spencer@ccrma.stanford.edu)// date: Autumn 2005//-----------------------------------------------------------------------------#include "chuck_shell.h"#include "chuck_otf.h"#include "chuck_globals.h"#include "chuck_errmsg.h"#include "util_network.h"#include "util_string.h" #include <stdio.h>#include <errno.h>#include <ctype.h>#ifndef __PLATFORM_WIN32__ #include <unistd.h> #include <sys/param.h> #include <sys/types.h> #include <dirent.h>#endif using namespace std; // REFACTOR-2017: TODO Ge: where should this live? not in chuck_main if it's in core!// global shell pointer (lives in chuck_main)Chuck_Shell * g_shell; //-----------------------------------------------------------------------------// name: tokenize_string// desc: divides a string into space separated tokens, respecting single and // double quotes//-----------------------------------------------------------------------------void tokenize_string( string str, vector< string > & tokens){ t_CKINT space = 1; t_CKINT end_space = 0; t_CKINT squote = 0; t_CKINT dquote = 0; t_CKINT i = 0, j = 0, len = str.size(); for( i = 0; i < len; i++ ) { if( isspace( str[i] ) && space ) { j++; continue; } if( isspace( str[i] ) && end_space ) { tokens.push_back( string( str, j, i - j ) ); j = i + 1; space = 1; end_space = 0; continue; } if( str[i] == '\'' ) { if( dquote ) continue; if( !squote ) { str.erase( i, 1 ); len--; i--; space = 0; end_space = 0; squote = 1; continue; } else if( str[i - 1] == '\\' ) { str.erase( i - 1, 1 ); len--; i--; continue; } else { str.erase( i, 1 ); len--; i--; squote = 0; end_space = 1; space = 0; continue; } } if( str[i] == '"' ) //" { if( squote ) continue; if( !dquote ) { str.erase( i, 1 ); i--; len--; space = 0; end_space = 0; dquote = 1; continue; } else if( str[i - 1] == '\\' ) { str.erase( i - 1, 1 ); len--; i--; continue; } else { str.erase( i, 1 ); i--; len--; dquote = 0; end_space = 1; space = 0; continue; } } if( !squote && !dquote ) { end_space = 1; space = 0; } } if( i > j && end_space ) { tokens.push_back( string( str, j, i - j ) ); }} //-----------------------------------------------------------------------------// name: win32_tmpnam()// desc: replacement for broken tmpnam() on Windows Vista + 7// file_path should be at least MAX_PATH characters. //-----------------------------------------------------------------------------#ifdef __PLATFORM_WIN32__ #include <windows.h> int win32_tmpnam(char *file_path){ char tmp_path[MAX_PATH]; if(GetTempPath(256, tmp_path) == 0) return 0; if(GetTempFileName(tmp_path, "cksh", 0, file_path) == 0) return 0; return 1;} #endif //-----------------------------------------------------------------------------// name: shell_cb// desc: thread routine//-----------------------------------------------------------------------------void * shell_cb( void * p ){ Chuck_Shell * shell; // log EM_log( CK_LOG_INFO, "starting thread routine for shell..." ); // assuming this is absolutely necessary, an assert may be better assert( p != NULL ); shell = ( Chuck_Shell * ) p; //atexit( wait_for_shell ); // run the shell shell->run(); // delete and set to NULL SAFE_DELETE( g_shell ); // perhaps let shell destructor clean up mode and ui? EM_log( CK_LOG_INFO, "exiting thread routine for shell..." ); return NULL;} //-----------------------------------------------------------------------------// name: Chuck_Shell()// desc: ...//-----------------------------------------------------------------------------Chuck_Shell::Chuck_Shell(){ ui = NULL; process_vm = NULL; current_vm = NULL; initialized = FALSE; stop = FALSE; code_entry_active = FALSE;} //-----------------------------------------------------------------------------// name: ~Chuck_Shell()// desc: ...//-----------------------------------------------------------------------------Chuck_Shell::~Chuck_Shell(){ vector<string>::size_type i, len = allocated_commands.size(); //iterate through commands, delete the associated heap data for( i = 0; i != len; i++ ) SAFE_DELETE( allocated_commands[i] ); // delete ui SAFE_DELETE( ui ); // flag initialized = FALSE;} //-----------------------------------------------------------------------------// name: init()// desc: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_Shell::init( Chuck_VM * vm, Chuck_Shell_UI * ui ){ // log EM_log( CK_LOG_SYSTEM, "initializing chuck shell..." ); // check if( initialized == TRUE ) { EM_log( CK_LOG_WARNING, "chuck shell already initialized" ); return TRUE; } // ui if( ui == NULL ) { CK_FPRINTF_STDERR( "[chuck](via shell): NULL ui passed to Chuck_Shell::init..." ); return FALSE; } this->ui = ui; process_vm = vm; Chuck_Shell_Network_VM * cspv = new Chuck_Shell_Network_VM(); if( !cspv->init( "localhost", 8888 ) ) { CK_FPRINTF_STDERR( "[chuck](via shell): error initializing process VM..." ); SAFE_DELETE( cspv ); return FALSE; } current_vm = cspv; vms.push_back( current_vm->copy() ); process_vm = vm; code_entry_active = FALSE; code = ""; // init default variables variables["COMMAND_PROMPT"] = "chuck %> "; variables["DEFAULT_CONTEXT"] = "shell_global"; // initialize prompt prompt = variables["COMMAND_PROMPT"]; Command * temp; // initialize the string -> Chuck_Shell_Command map temp = new Command_VM(); temp->init( this ); commands["vm"] = temp; allocated_commands.push_back( temp ); temp = new Command_VMList(); temp->init( this ); commands["vms"] = temp; allocated_commands.push_back( temp ); temp = new Command_Add(); temp->init( this ); commands["+"] = temp; commands["add"] = temp; allocated_commands.push_back( temp ); temp = new Command_Remove(); temp->init( this ); commands["-"] = temp; commands["remove"] = temp; allocated_commands.push_back( temp ); temp = new Command_Status(); temp->init( this ); commands["status"] = temp; commands["^"] = temp; allocated_commands.push_back( temp ); temp = new Command_Removeall(); temp->init( this ); commands["removeall"] = temp; allocated_commands.push_back( temp ); temp = new Command_Removelast(); temp->init( this ); commands["--"] = temp; allocated_commands.push_back( temp ); temp = new Command_Replace(); temp->init( this ); commands["replace"] = temp; commands["="] = temp; allocated_commands.push_back( temp ); temp = new Command_Close(); temp->init( this ); commands["close"] = temp; allocated_commands.push_back( temp ); temp = new Command_Kill(); temp->init( this ); commands["kill"] = temp; allocated_commands.push_back( temp ); temp = new Command_Exit(); temp->init( this ); commands["exit"] = temp; commands["quit"] = temp; allocated_commands.push_back( temp ); temp = new Command_Ls(); temp->init( this ); commands["ls"] = temp; allocated_commands.push_back( temp ); temp = new Command_Pwd(); temp->init( this ); commands["pwd"] = temp; allocated_commands.push_back( temp ); temp = new Command_Cd(); temp->init( this ); commands["cd"] = temp; allocated_commands.push_back( temp ); temp = new Command_Alias(); temp->init( this ); commands["alias"] = temp; allocated_commands.push_back( temp ); temp = new Command_Unalias(); temp->init( this ); commands["unalias"] = temp; allocated_commands.push_back( temp ); temp = new Command_Source(); temp->init( this ); commands["source"] = temp; commands["."] = temp; allocated_commands.push_back( temp ); temp = new Command_Code(); temp->init( this ); commands["code"] = temp; allocated_commands.push_back( temp ); // flag initialized = TRUE; return TRUE;} //-----------------------------------------------------------------------------// name: run()// desc: ...//-----------------------------------------------------------------------------void Chuck_Shell::run(){ // log EM_log( CK_LOG_SYSTEM, "running chuck shell..." ); // make sure if(initialized == FALSE) { CK_FPRINTF_STDERR( "[chuck](via shell): shell not initialized...\n" ); return; } string command; string result; ui->next_result( "welcome to chuck shell!\n" ); // ui->next_result( "(type \"help\" for more information)\n" ); // loop for( ; !stop; ) { // get command if( ui->next_command( prompt, command ) == TRUE ) { // result.clear(); result = ""; //printf( "chuck_shell::run\n" ); // execute the command execute( command, result ); // command.clear(); command = ""; // pass the result to the shell ui ui->next_result( result ); } else // done break; } // log EM_log( CK_LOG_SYSTEM, "exiting chuck shell..." );} //-----------------------------------------------------------------------------// name: execute// desc: ...//-----------------------------------------------------------------------------t_CKBOOL Chuck_Shell::execute( string & in, string & out ){ if( !initialized ) { return FALSE; } // vector of string tokens vector< string > vec; // clear the response out = ""; // first find out if this is code to run if( !code_entry_active && in[in.find_first_not_of( " \t\v\n" )] == '{' ) start_code(); if( code_entry_active ) { continue_code( in ); if( code_entry_active == FALSE ) { //strip opening and closing braces string::size_type k = code.find( "{" ); string head = string( code, 0, k ); code = string( code, k + 1, code.size() - k - 1 ); k = code.rfind( "}" ); string tail = string( code, k + 1, code.size() - k - 1 ); code = string( code, 0, k ); do_code( code, out );Lines 1–500 of 2260. Load more
/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // file: chuck_shell.cpp // desc: chuck shell implementation // // author: Spencer Salazar (spencer@ccrma.stanford.edu) // date: Autumn 2005 //----------------------------------------------------------------------------- #include "chuck_shell.h" #include "chuck_otf.h" #include "chuck_globals.h" #include "chuck_errmsg.h" #include "util_network.h" #include "util_string.h" #include <stdio.h> #include <errno.h> #include <ctype.h> #ifndef __PLATFORM_WIN32__ #include <unistd.h> #include <sys/param.h> #include <sys/types.h> #include <dirent.h> #endif using namespace std; // REFACTOR-2017: TODO Ge: where should this live? not in chuck_main if it's in core! // global shell pointer (lives in chuck_main) Chuck_Shell * g_shell; //----------------------------------------------------------------------------- // name: tokenize_string // desc: divides a string into space separated tokens, respecting single and // double quotes //----------------------------------------------------------------------------- void tokenize_string( string str, vector< string > & tokens) { t_CKINT space = 1; t_CKINT end_space = 0; t_CKINT squote = 0; t_CKINT dquote = 0; t_CKINT i = 0, j = 0, len = str.size(); for( i = 0; i < len; i++ ) { if( isspace( str[i] ) && space ) { j++; continue; } if( isspace( str[i] ) && end_space ) { tokens.push_back( string( str, j, i - j ) ); j = i + 1; space = 1; end_space = 0; continue; } if( str[i] == '\'' ) { if( dquote ) continue; if( !squote ) { str.erase( i, 1 ); len--; i--; space = 0; end_space = 0; squote = 1; continue; } else if( str[i - 1] == '\\' ) { str.erase( i - 1, 1 ); len--; i--; continue; } else { str.erase( i, 1 ); len--; i--; squote = 0; end_space = 1; space = 0; continue; } } if( str[i] == '"' ) //" { if( squote ) continue; if( !dquote ) { str.erase( i, 1 ); i--; len--; space = 0; end_space = 0; dquote = 1; continue; } else if( str[i - 1] == '\\' ) { str.erase( i - 1, 1 ); len--; i--; continue; } else { str.erase( i, 1 ); i--; len--; dquote = 0; end_space = 1; space = 0; continue; } } if( !squote && !dquote ) { end_space = 1; space = 0; } } if( i > j && end_space ) { tokens.push_back( string( str, j, i - j ) ); } } //----------------------------------------------------------------------------- // name: win32_tmpnam() // desc: replacement for broken tmpnam() on Windows Vista + 7 // file_path should be at least MAX_PATH characters. //----------------------------------------------------------------------------- #ifdef __PLATFORM_WIN32__ #include <windows.h> int win32_tmpnam(char *file_path) { char tmp_path[MAX_PATH]; if(GetTempPath(256, tmp_path) == 0) return 0; if(GetTempFileName(tmp_path, "cksh", 0, file_path) == 0) return 0; return 1; } #endif //----------------------------------------------------------------------------- // name: shell_cb // desc: thread routine //----------------------------------------------------------------------------- void * shell_cb( void * p ) { Chuck_Shell * shell; // log EM_log( CK_LOG_INFO, "starting thread routine for shell..." ); // assuming this is absolutely necessary, an assert may be better assert( p != NULL ); shell = ( Chuck_Shell * ) p; //atexit( wait_for_shell ); // run the shell shell->run(); // delete and set to NULL SAFE_DELETE( g_shell ); // perhaps let shell destructor clean up mode and ui? EM_log( CK_LOG_INFO, "exiting thread routine for shell..." ); return NULL; } //----------------------------------------------------------------------------- // name: Chuck_Shell() // desc: ... //----------------------------------------------------------------------------- Chuck_Shell::Chuck_Shell() { ui = NULL; process_vm = NULL; current_vm = NULL; initialized = FALSE; stop = FALSE; code_entry_active = FALSE; } //----------------------------------------------------------------------------- // name: ~Chuck_Shell() // desc: ... //----------------------------------------------------------------------------- Chuck_Shell::~Chuck_Shell() { vector<string>::size_type i, len = allocated_commands.size(); //iterate through commands, delete the associated heap data for( i = 0; i != len; i++ ) SAFE_DELETE( allocated_commands[i] ); // delete ui SAFE_DELETE( ui ); // flag initialized = FALSE; } //----------------------------------------------------------------------------- // name: init() // desc: ... //----------------------------------------------------------------------------- t_CKBOOL Chuck_Shell::init( Chuck_VM * vm, Chuck_Shell_UI * ui ) { // log EM_log( CK_LOG_SYSTEM, "initializing chuck shell..." ); // check if( initialized == TRUE ) { EM_log( CK_LOG_WARNING, "chuck shell already initialized" ); return TRUE; } // ui if( ui == NULL ) { CK_FPRINTF_STDERR( "[chuck](via shell): NULL ui passed to Chuck_Shell::init..." ); return FALSE; } this->ui = ui; process_vm = vm; Chuck_Shell_Network_VM * cspv = new Chuck_Shell_Network_VM(); if( !cspv->init( "localhost", 8888 ) ) { CK_FPRINTF_STDERR( "[chuck](via shell): error initializing process VM..." ); SAFE_DELETE( cspv ); return FALSE; } current_vm = cspv; vms.push_back( current_vm->copy() ); process_vm = vm; code_entry_active = FALSE; code = ""; // init default variables variables["COMMAND_PROMPT"] = "chuck %> "; variables["DEFAULT_CONTEXT"] = "shell_global"; // initialize prompt prompt = variables["COMMAND_PROMPT"]; Command * temp; // initialize the string -> Chuck_Shell_Command map temp = new Command_VM(); temp->init( this ); commands["vm"] = temp; allocated_commands.push_back( temp ); temp = new Command_VMList(); temp->init( this ); commands["vms"] = temp; allocated_commands.push_back( temp ); temp = new Command_Add(); temp->init( this ); commands["+"] = temp; commands["add"] = temp; allocated_commands.push_back( temp ); temp = new Command_Remove(); temp->init( this ); commands["-"] = temp; commands["remove"] = temp; allocated_commands.push_back( temp ); temp = new Command_Status(); temp->init( this ); commands["status"] = temp; commands["^"] = temp; allocated_commands.push_back( temp ); temp = new Command_Removeall(); temp->init( this ); commands["removeall"] = temp; allocated_commands.push_back( temp ); temp = new Command_Removelast(); temp->init( this ); commands["--"] = temp; allocated_commands.push_back( temp ); temp = new Command_Replace(); temp->init( this ); commands["replace"] = temp; commands["="] = temp; allocated_commands.push_back( temp ); temp = new Command_Close(); temp->init( this ); commands["close"] = temp; allocated_commands.push_back( temp ); temp = new Command_Kill(); temp->init( this ); commands["kill"] = temp; allocated_commands.push_back( temp ); temp = new Command_Exit(); temp->init( this ); commands["exit"] = temp; commands["quit"] = temp; allocated_commands.push_back( temp ); temp = new Command_Ls(); temp->init( this ); commands["ls"] = temp; allocated_commands.push_back( temp ); temp = new Command_Pwd(); temp->init( this ); commands["pwd"] = temp; allocated_commands.push_back( temp ); temp = new Command_Cd(); temp->init( this ); commands["cd"] = temp; allocated_commands.push_back( temp ); temp = new Command_Alias(); temp->init( this ); commands["alias"] = temp; allocated_commands.push_back( temp ); temp = new Command_Unalias(); temp->init( this ); commands["unalias"] = temp; allocated_commands.push_back( temp ); temp = new Command_Source(); temp->init( this ); commands["source"] = temp; commands["."] = temp; allocated_commands.push_back( temp ); temp = new Command_Code(); temp->init( this ); commands["code"] = temp; allocated_commands.push_back( temp ); // flag initialized = TRUE; return TRUE; } //----------------------------------------------------------------------------- // name: run() // desc: ... //----------------------------------------------------------------------------- void Chuck_Shell::run() { // log EM_log( CK_LOG_SYSTEM, "running chuck shell..." ); // make sure if(initialized == FALSE) { CK_FPRINTF_STDERR( "[chuck](via shell): shell not initialized...\n" ); return; } string command; string result; ui->next_result( "welcome to chuck shell!\n" ); // ui->next_result( "(type \"help\" for more information)\n" ); // loop for( ; !stop; ) { // get command if( ui->next_command( prompt, command ) == TRUE ) { // result.clear(); result = ""; //printf( "chuck_shell::run\n" ); // execute the command execute( command, result ); // command.clear(); command = ""; // pass the result to the shell ui ui->next_result( result ); } else // done break; } // log EM_log( CK_LOG_SYSTEM, "exiting chuck shell..." ); } //----------------------------------------------------------------------------- // name: execute // desc: ... //----------------------------------------------------------------------------- t_CKBOOL Chuck_Shell::execute( string & in, string & out ) { if( !initialized ) { return FALSE; } // vector of string tokens vector< string > vec; // clear the response out = ""; // first find out if this is code to run if( !code_entry_active && in[in.find_first_not_of( " \t\v\n" )] == '{' ) start_code(); if( code_entry_active ) { continue_code( in ); if( code_entry_active == FALSE ) { //strip opening and closing braces string::size_type k = code.find( "{" ); string head = string( code, 0, k ); code = string( code, k + 1, code.size() - k - 1 ); k = code.rfind( "}" ); string tail = string( code, k + 1, code.size() - k - 1 ); code = string( code, 0, k ); do_code( code, out );