This patch sprinkles a few const qualifiers about, and inserts "void"
as the formal parameter list of a couple of functions.
Mostly, though, this patch is an experiment and a proof of principle.
You may not want to apply it in its present form.
The experiment concerns the way we invoke a child process, using an
exclamation point as an escape. So far, I have compiled with
EXEC_DEFAULT undefined, so I'm not using the pipe that we open to
bash. Under these conditions, when we invoke a child process, the
results aren't very satisfying.
The reason is that we don't pass the command to a shell. We parse it
with strtok() and then pass an array of arguments to the program
identified by the first token. As a result:
- We don't expand environmental variables.
- We don't expand wild cards.
- We can't use input or output redirection.
- We can't invoke another layer of subshell, as with backticks.
- We can't access shell built-ins.
In short, we can't harness the rich language processing that a shell
normally applies before passing arguments to programs. Even trivial
commands like:
srfsh# !ls *.o
...don't work as expected. As a result, the escaping is very
limited in its usefulness, probably leaving a typical user both
frustrated and baffled.
Using the pipe-to-bash approach would presumably eliminate most of
these problems, but not all. For example, if we enter:
srfsh# echo "Hello, World!"
...the result will be to display "Hello, World!" instead of
"Hello, World!". By dismembering the command with strtok()
and then reassembling it, we lose the extra embedded spaces.
In any event, the pipe-to-bash approach applies only when EXEC_DEFAULT
is defined, and only when the command we enter is otherwise invalid
to srfsh.
-------------
The experimental solution is to pass the original command (minus the
opening exclamation point) to the system() function, which in turn
passes it to an instance of /bin/sh. Then sh does all the things it
normally does.
On my system sh is linked to bash. I don't think this sh behaves
like a true Bourne shell, but is just an alias for bash. For example
it implements the "let" built-in, which I don't think a true Bourne
shell recognizes.
In any case we may or may not want to use sh. We might want to
always use bash. Or we might want to look at $SHELL to see what the
user is accustomed to.
I don't think that this patch is a final solution, because it needs
to be cleaned up in some respects. However I believe that it is a
step in a useful direction.
Scott McKellar
http://home.swbell.net/mck9/ct/*** trunk/src/srfsh/srfsh.c 2007-07-09 19:06:30.000000000 -0500
--- trunk-mod/src/srfsh/srfsh.c 2007-07-09 21:39:40.000000000 -0500
***************
*** 56,69 ****
static int send_request( char* server,
char* method, growing_buffer* buffer, int relay );
static int parse_error( char* words[] );
! static int router_query_servers( char* server );
//static int srfsh_client_connect();
! static int print_help();
//static char* tabs(int count);
static void sig_child_handler( int s );
//static void sig_int_handler( int s );
! static int load_history();
static int handle_math( char* words[] );
static int do_math( int count, int style );
static int handle_introspect(char* words[]);
--- 56,69 ----
static int send_request( char* server,
char* method, growing_buffer* buffer, int relay );
static int parse_error( char* words[] );
! static int router_query_servers( const char* server );
//static int srfsh_client_connect();
! static int print_help( void );
//static char* tabs(int count);
static void sig_child_handler( int s );
//static void sig_int_handler( int s );
! static int load_history( void );
static int handle_math( char* words[] );
static int do_math( int count, int style );
static int handle_introspect(char* words[]);
***************
*** 167,173 ****
}
*/
! static int load_history() {
char* home = getenv("HOME");
int l = strlen(home) + 24;
--- 167,173 ----
}
*/
! static int load_history( void ) {
char* home = getenv("HOME");
int l = strlen(home) + 24;
***************
*** 213,218 ****
--- 213,220 ----
if( request == NULL )
return 0;
+ char * original_request = strdup( request );
+
int ret_val = 0;
int i = 0;
char* words[COMMAND_BUFSIZE];
***************
*** 222,228 ****
--- 224,233 ----
char* cur_tok = strtok( req, " " );
if( cur_tok == NULL )
+ {
+ free( original_request );
return 0;
+ }
while(cur_tok != NULL) {
words[i++] = cur_tok;
***************
*** 266,274 ****
else if (!strcmp(words[0],"login"))
ret_val = handle_login(words);
! else if (words[0][0] == '!')
! ret_val = handle_exec( words, 1 );
if(!ret_val) {
#ifdef EXEC_DEFAULT
return handle_exec( words, 0 );
--- 271,284 ----
else if (!strcmp(words[0],"login"))
ret_val = handle_login(words);
! else if (words[0][0] == '!') {
! //ret_val = handle_exec( words, 1 );
! system( original_request + 1 );
! ret_val = 1;
! }
+ free( original_request );
+
if(!ret_val) {
#ifdef EXEC_DEFAULT
return handle_exec( words, 0 );
***************
*** 758,764 ****
! static int router_query_servers( char* router_server ) {
if( ! router_server || strlen(router_server) == 0 )
return 0;
--- 768,774 ----
! static int router_query_servers( const char* router_server ) {
if( ! router_server || strlen(router_server) == 0 )
return 0;
***************
*** 795,801 ****
return 1;
}
! static int print_help() {
printf(
"---------------------------------------------------------------------------------\n"
--- 805,811 ----
return 1;
}
! static int print_help( void ) {
printf(
"---------------------------------------------------------------------------------\n"