2005-09-20 23:26:39 +10:00
/*
2008-01-13 05:18:48 +10:00
Copyright ( C ) 2005 - 2008 Axel Liljencrantz
2005-09-20 23:26:39 +10:00
2006-11-02 00:47:47 +10:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation .
2005-09-20 23:26:39 +10:00
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 , USA .
*/
2008-01-13 05:21:35 +10:00
/** \file fish.c
2005-09-20 23:26:39 +10:00
The main loop of < tt > fish < / tt > .
*/
# include "config.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <unistd.h>
# include <termios.h>
# include <fcntl.h>
# ifdef HAVE_GETOPT_H
# include <getopt.h>
# endif
# include <locale.h>
# include <signal.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "common.h"
# include "reader.h"
# include "builtin.h"
# include "function.h"
# include "complete.h"
# include "wutil.h"
# include "env.h"
# include "sanity.h"
# include "proc.h"
# include "parser.h"
# include "expand.h"
# include "intern.h"
2005-10-06 08:37:08 +10:00
# include "exec.h"
# include "event.h"
2005-10-15 10:51:26 +10:00
# include "output.h"
2006-10-19 21:50:23 +10:00
# include "halloc.h"
2006-02-10 01:50:20 +10:00
# include "halloc_util.h"
2006-04-20 09:42:11 +10:00
# include "history.h"
2006-10-19 21:50:23 +10:00
# include "path.h"
2005-09-20 23:26:39 +10:00
2006-05-18 23:00:39 +10:00
/**
The string describing the single - character options accepted by the main fish binary
*/
2010-10-03 11:46:26 +08:00
# define GETOPT_STRING "+hilnvc:p:d:"
2006-03-10 23:38:09 +10:00
2005-09-20 23:26:39 +10:00
/**
Parse init files
*/
static int read_init ( )
{
2006-10-19 21:50:23 +10:00
wchar_t * config_dir ;
wchar_t * config_dir_escaped ;
void * context ;
string_buffer_t * eval_buff ;
2005-09-20 23:26:39 +10:00
2008-01-09 10:43:39 +10:00
eval ( L " builtin . " DATADIR " /fish/config.fish 2>/dev/null " , 0 , TOP ) ;
eval ( L " builtin . " SYSCONFDIR L " /fish/config.fish 2>/dev/null " , 0 , TOP ) ;
2011-12-26 19:18:46 -08:00
2006-10-19 21:50:23 +10:00
/*
We need to get the configuration directory before we can source the user configuration file
*/
context = halloc ( 0 , 0 ) ;
eval_buff = sb_halloc ( context ) ;
config_dir = path_get_config ( context ) ;
2007-04-11 23:18:23 +10:00
/*
If config_dir is null then we have no configuration directory
and no custom config to load .
*/
if ( config_dir )
{
config_dir_escaped = escape ( config_dir , 1 ) ;
2008-01-09 10:43:39 +10:00
sb_printf ( eval_buff , L " builtin . %ls/config.fish 2>/dev/null " , config_dir_escaped ) ;
2007-04-11 23:18:23 +10:00
eval ( ( wchar_t * ) eval_buff - > buff , 0 , TOP ) ;
free ( config_dir_escaped ) ;
}
2011-12-26 19:18:46 -08:00
2006-10-19 21:50:23 +10:00
halloc_free ( context ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
return 1 ;
}
2008-01-14 02:47:47 +10:00
/**
2008-01-09 11:23:38 +10:00
Parse the argument list , return the index of the first non - switch
arguments .
*/
2012-01-14 22:32:45 -08:00
static int fish_parse_opt ( int argc , char * * argv , const char * * cmd_ptr )
2005-09-20 23:26:39 +10:00
{
int my_optind ;
2006-10-26 06:54:43 +10:00
int force_interactive = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
while ( 1 )
{
static struct option
long_options [ ] =
{
{
2011-12-26 19:18:46 -08:00
" command " , required_argument , 0 , ' c '
2005-09-20 23:26:39 +10:00
}
,
2006-02-23 01:41:52 +10:00
{
2011-12-26 19:18:46 -08:00
" debug-level " , required_argument , 0 , ' d '
2006-02-23 01:41:52 +10:00
}
,
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
" interactive " , no_argument , 0 , ' i '
2005-09-20 23:26:39 +10:00
}
,
2006-02-03 10:37:54 +10:00
{
2011-12-26 19:18:46 -08:00
" login " , no_argument , 0 , ' l '
2006-02-03 10:37:54 +10:00
}
,
2006-03-18 11:04:59 +10:00
{
2011-12-26 19:18:46 -08:00
" no-execute " , no_argument , 0 , ' n '
2006-03-18 11:04:59 +10:00
}
,
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
" profile " , required_argument , 0 , ' p '
2005-09-20 23:26:39 +10:00
}
,
{
2011-12-26 19:18:46 -08:00
" help " , no_argument , 0 , ' h '
2005-09-20 23:26:39 +10:00
}
,
{
2011-12-26 19:18:46 -08:00
" version " , no_argument , 0 , ' v '
2005-09-20 23:26:39 +10:00
}
,
2011-12-26 19:18:46 -08:00
{
0 , 0 , 0 , 0
2005-09-20 23:26:39 +10:00
}
}
;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
int opt_index = 0 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
int opt = getopt_long ( argc ,
2011-12-26 19:18:46 -08:00
argv ,
2006-05-18 23:00:39 +10:00
GETOPT_STRING ,
2011-12-26 19:18:46 -08:00
long_options ,
2005-09-20 23:26:39 +10:00
& opt_index ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( opt = = - 1 )
break ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
switch ( opt )
{
case 0 :
2006-07-22 20:16:51 +10:00
{
2005-09-20 23:26:39 +10:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
case ' c ' :
2006-07-22 20:16:51 +10:00
{
2011-12-26 19:18:46 -08:00
* cmd_ptr = optarg ;
2005-09-20 23:26:39 +10:00
is_interactive_session = 0 ;
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
case ' d ' :
2006-02-23 01:41:52 +10:00
{
char * end ;
2007-01-09 23:41:17 +10:00
int tmp ;
errno = 0 ;
tmp = strtol ( optarg , & end , 10 ) ;
2011-12-26 19:18:46 -08:00
2007-01-09 23:41:17 +10:00
if ( tmp > = 0 & & tmp < = 10 & & ! * end & & ! errno )
2006-02-23 01:41:52 +10:00
{
debug_level = tmp ;
}
else
{
debug ( 0 , _ ( L " Invalid value '%s' for debug level switch " ) , optarg ) ;
exit ( 1 ) ;
}
break ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case ' h ' :
2006-07-22 20:16:51 +10:00
{
2007-01-17 23:12:46 +10:00
* cmd_ptr = " __fish_print_help fish " ;
2005-09-20 23:26:39 +10:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case ' i ' :
2006-07-22 20:16:51 +10:00
{
2005-09-20 23:26:39 +10:00
force_interactive = 1 ;
2011-12-26 19:18:46 -08:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2006-02-03 10:37:54 +10:00
case ' l ' :
2006-07-22 20:16:51 +10:00
{
2006-02-03 10:37:54 +10:00
is_login = 1 ;
2011-12-26 19:18:46 -08:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2006-03-18 11:04:59 +10:00
case ' n ' :
2006-07-22 20:16:51 +10:00
{
2006-03-18 11:04:59 +10:00
no_exec = 1 ;
2011-12-26 19:18:46 -08:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case ' p ' :
2006-07-22 20:16:51 +10:00
{
2005-09-20 23:26:39 +10:00
profile = optarg ;
2011-12-26 19:18:46 -08:00
break ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case ' v ' :
2006-07-22 20:16:51 +10:00
{
2011-12-26 19:18:46 -08:00
fwprintf ( stderr ,
_ ( L " %s, version %s \n " ) ,
2005-09-20 23:26:39 +10:00
PACKAGE_NAME ,
PACKAGE_VERSION ) ;
2011-12-26 19:18:46 -08:00
exit ( 0 ) ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
case ' ? ' :
2006-07-22 20:16:51 +10:00
{
2006-10-26 06:54:43 +10:00
exit ( 1 ) ;
2006-07-22 20:16:51 +10:00
}
2011-12-26 19:18:46 -08:00
}
2005-09-20 23:26:39 +10:00
}
my_optind = optind ;
2011-12-26 19:18:46 -08:00
2006-02-19 11:14:32 +10:00
is_login | = ( strcmp ( argv [ 0 ] , " -fish " ) = = 0 ) ;
2011-12-26 19:18:46 -08:00
2008-01-09 11:23:38 +10:00
/*
We are an interactive session if we have not been given an
explicit command to execute , _and_ stdin is a tty .
*/
2006-10-26 06:54:43 +10:00
is_interactive_session & = ( * cmd_ptr = = 0 ) ;
2005-09-20 23:26:39 +10:00
is_interactive_session & = ( my_optind = = argc ) ;
2011-12-26 19:18:46 -08:00
is_interactive_session & = isatty ( STDIN_FILENO ) ;
2008-01-09 11:23:38 +10:00
/*
We are also an interactive session if we have are forced -
*/
2006-02-03 10:37:54 +10:00
is_interactive_session | = force_interactive ;
2006-01-04 22:51:02 +10:00
2006-10-26 06:54:43 +10:00
return my_optind ;
}
/**
Calls a bunch of init functions , parses the init files and then
parses commands from stdin or files , depending on arguments
*/
int main ( int argc , char * * argv )
{
2012-01-02 13:40:03 -08:00
struct stat tmp ;
2006-10-26 06:54:43 +10:00
int res = 1 ;
2012-01-14 22:32:45 -08:00
const char * cmd = 0 ;
2006-10-26 06:54:43 +10:00
int my_optind = 0 ;
2011-12-26 19:18:46 -08:00
halloc_util_init ( ) ;
2012-01-05 13:58:48 -08:00
set_main_thread ( ) ;
2006-10-26 06:54:43 +10:00
wsetlocale ( LC_ALL , L " " ) ;
is_interactive_session = 1 ;
program_name = L " fish " ;
2012-01-03 10:54:06 -08:00
stat ( " ----------FISH_HIT_MAIN---------- " , & tmp ) ;
2006-11-11 20:48:40 +10:00
2006-10-26 06:54:43 +10:00
my_optind = fish_parse_opt ( argc , argv , & cmd ) ;
2006-03-18 11:04:59 +10:00
/*
No - exec is prohibited when in interactive mode
*/
if ( is_interactive_session & & no_exec )
{
debug ( 1 , _ ( L " Can not use the no-execute mode when running an interactive session " ) ) ;
no_exec = 0 ;
}
2011-12-26 19:18:46 -08:00
proc_init ( ) ;
event_init ( ) ;
2005-11-03 01:41:59 +10:00
wutil_init ( ) ;
2005-09-20 23:26:39 +10:00
parser_init ( ) ;
builtin_init ( ) ;
function_init ( ) ;
env_init ( ) ;
2005-10-25 19:39:45 +10:00
reader_init ( ) ;
2006-04-19 19:55:02 +10:00
history_init ( ) ;
2006-03-10 23:38:09 +10:00
2005-09-20 23:26:39 +10:00
if ( read_init ( ) )
{
if ( cmd ! = 0 )
{
wchar_t * cmd_wcs = str2wcs ( cmd ) ;
res = eval ( cmd_wcs , 0 , TOP ) ;
free ( cmd_wcs ) ;
2006-05-14 20:16:23 +10:00
reader_exit ( 0 , 0 ) ;
2005-09-20 23:26:39 +10:00
}
else
{
if ( my_optind = = argc )
{
2010-09-18 20:26:54 +08:00
res = reader_read ( STDIN_FILENO , 0 ) ;
2005-09-20 23:26:39 +10:00
}
else
{
2011-12-26 19:18:46 -08:00
char * * ptr ;
2010-10-03 11:46:26 +08:00
char * file = * ( argv + ( my_optind + + ) ) ;
2011-12-26 19:18:46 -08:00
int i ;
2005-09-20 23:26:39 +10:00
string_buffer_t sb ;
2005-10-19 22:07:44 +10:00
int fd ;
2006-02-03 01:23:56 +10:00
wchar_t * rel_filename , * abs_filename ;
2011-12-26 19:18:46 -08:00
2005-10-19 22:07:44 +10:00
if ( ( fd = open ( file , O_RDONLY ) ) = = - 1 )
2005-09-20 23:26:39 +10:00
{
wperror ( L " open " ) ;
return 1 ;
}
2010-10-03 11:46:26 +08:00
if ( * ( argv + my_optind ) )
2005-09-20 23:26:39 +10:00
{
2006-04-19 19:58:18 +10:00
sb_init ( & sb ) ;
2011-12-26 19:18:46 -08:00
2010-10-03 11:46:26 +08:00
for ( i = 1 , ptr = argv + my_optind ; * ptr ; i + + , ptr + + )
2005-09-20 23:26:39 +10:00
{
if ( i ! = 1 )
sb_append ( & sb , ARRAY_SEP_STR ) ;
wchar_t * val = str2wcs ( * ptr ) ;
sb_append ( & sb , val ) ;
free ( val ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
env_set ( L " argv " , ( wchar_t * ) sb . buff , 0 ) ;
sb_destroy ( & sb ) ;
}
2006-02-03 01:23:56 +10:00
rel_filename = str2wcs ( file ) ;
2006-02-03 10:38:55 +10:00
abs_filename = wrealpath ( rel_filename , 0 ) ;
2007-09-09 08:24:53 +10:00
2006-02-03 10:38:55 +10:00
if ( ! abs_filename )
2007-09-09 08:24:53 +10:00
{
2006-02-03 10:38:55 +10:00
abs_filename = wcsdup ( rel_filename ) ;
2007-09-09 08:24:53 +10:00
}
2006-02-03 01:23:56 +10:00
reader_push_current_filename ( intern ( abs_filename ) ) ;
free ( rel_filename ) ;
free ( abs_filename ) ;
2006-02-03 10:37:54 +10:00
2007-04-26 04:30:02 +10:00
res = reader_read ( fd , 0 ) ;
2005-09-20 23:26:39 +10:00
if ( res )
{
2011-12-26 19:18:46 -08:00
debug ( 1 ,
_ ( L " Error while reading file %ls \n " ) ,
2007-09-09 08:24:53 +10:00
reader_current_filename ( ) ? reader_current_filename ( ) : _ ( L " Standard input " ) ) ;
2011-12-26 19:18:46 -08:00
}
2006-02-03 01:23:56 +10:00
reader_pop_current_filename ( ) ;
2005-09-20 23:26:39 +10:00
}
}
}
2011-12-26 19:18:46 -08:00
2006-05-14 20:16:23 +10:00
proc_fire_event ( L " PROCESS_EXIT " , EVENT_EXIT , getpid ( ) , res ) ;
2011-12-26 19:18:46 -08:00
2006-04-19 19:55:02 +10:00
history_destroy ( ) ;
2005-09-20 23:26:39 +10:00
proc_destroy ( ) ;
builtin_destroy ( ) ;
function_destroy ( ) ;
reader_destroy ( ) ;
parser_destroy ( ) ;
wutil_destroy ( ) ;
2005-10-06 08:37:08 +10:00
event_destroy ( ) ;
2011-12-26 19:18:46 -08:00
2006-02-10 01:50:20 +10:00
halloc_util_destroy ( ) ;
2011-12-26 19:18:46 -08:00
2006-07-22 20:16:51 +10:00
env_destroy ( ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
intern_free_all ( ) ;
2011-12-26 19:18:46 -08:00
return res ? STATUS_UNKNOWN_COMMAND : proc_get_last_status ( ) ;
2005-09-20 23:26:39 +10:00
}