mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-22 03:51:15 -03:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec58ffa641 | ||
|
|
2c44ecb4a3 | ||
|
|
2eebb6e7ed | ||
|
|
1a3ab8a189 | ||
|
|
4722ddc373 | ||
|
|
25365dbc54 | ||
|
|
6a5f11879b | ||
|
|
b028e41f7f | ||
|
|
86593cd6a2 | ||
|
|
6cae5c8b0a | ||
|
|
29cd62ab6e | ||
|
|
4c7e06e752 | ||
|
|
433169dca4 | ||
|
|
d46dade284 | ||
|
|
79b466441b | ||
|
|
9f14d50974 | ||
|
|
990803009e | ||
|
|
6dfd629fc5 | ||
|
|
d97f8f3fde | ||
|
|
95ca3d1c69 | ||
|
|
c8b04f70cf | ||
|
|
bffff77d17 | ||
|
|
6bdb0cde8b | ||
|
|
42a260f1e6 | ||
|
|
148cb68700 | ||
|
|
18c185c256 | ||
|
|
b5b49e7a4d | ||
|
|
28ea5ce732 | ||
|
|
eccba7626d | ||
|
|
79d3207d51 | ||
|
|
d6bf879675 | ||
|
|
051f557e8f | ||
|
|
17171c3277 | ||
|
|
18a59291ed | ||
|
|
29e86254d0 | ||
|
|
b746a803a9 | ||
|
|
07e14ed7a8 | ||
|
|
df5cc6f858 | ||
|
|
409a407ca0 | ||
|
|
1c2cbb00bc | ||
|
|
bbf2a3836f |
@@ -72,7 +72,7 @@ COMMON_OBJS_WITH_HEADER := builtin_help.o
|
||||
|
||||
# main.c exists, but main.h does not, etc.
|
||||
COMMON_OBJS_WITH_CODE := builtin_set.o builtin_commandline.o \
|
||||
builtin_ulimit.o builtin_complete.o
|
||||
builtin_ulimit.o builtin_complete.o builtin_jobs.o
|
||||
|
||||
# All objects that the system needs to build fish
|
||||
FISH_OBJS := $(COMMON_OBJS) $(COMMON_OBJS_WITH_CODE) \
|
||||
|
||||
429
builtin.c
429
builtin.c
@@ -92,18 +92,6 @@ typedef struct builtin_data
|
||||
builtin_data_t;
|
||||
|
||||
|
||||
/**
|
||||
Print modes for the jobs builtin
|
||||
*/
|
||||
enum
|
||||
{
|
||||
JOBS_DEFAULT, /**< Print lots of general info */
|
||||
JOBS_PRINT_PID, /**< Print pid of each process in job */
|
||||
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
|
||||
JOBS_PRINT_GROUP, /**< Print group id of job */
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
Table of all builtins
|
||||
*/
|
||||
@@ -159,6 +147,15 @@ void builtin_wperror( const wchar_t *s)
|
||||
}
|
||||
}
|
||||
|
||||
static int count_char( const wchar_t *str, wchar_t c )
|
||||
{
|
||||
int res = 0;
|
||||
for( ; *str; str++ )
|
||||
{
|
||||
res += (*str==c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
Here follows the definition of all builtin commands. The function
|
||||
@@ -170,10 +167,12 @@ void builtin_wperror( const wchar_t *s)
|
||||
are part of the parser. (They are not parsed as commands, instead
|
||||
they only slightly alter the parser state)
|
||||
|
||||
If \c b is the buffer representing standard error, and the help
|
||||
message is about to be printed to an interactive screen, it may be
|
||||
shortened to fit the screen.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
|
||||
{
|
||||
const char *h;
|
||||
@@ -189,11 +188,50 @@ void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
|
||||
if( !h )
|
||||
return;
|
||||
|
||||
|
||||
|
||||
wchar_t *str = str2wcs(builtin_help_get( cmd ));
|
||||
wchar_t *str = str2wcs( h );
|
||||
if( str )
|
||||
{
|
||||
|
||||
if( is_interactive && !builtin_out_redirect && b==sb_err)
|
||||
{
|
||||
/* Interactive mode help to screen - only print synopsis if the rest won't fit */
|
||||
|
||||
int screen_height, lines;
|
||||
|
||||
screen_height = common_get_height();
|
||||
lines = count_char( str, L'\n' );
|
||||
if( lines > 2*screen_height/3 )
|
||||
{
|
||||
wchar_t *pos;
|
||||
|
||||
/* Find first empty line */
|
||||
for( pos=str; *pos; pos++ )
|
||||
{
|
||||
if( *pos == L'\n' )
|
||||
{
|
||||
wchar_t *pos2;
|
||||
int is_empty = 1;
|
||||
|
||||
for( pos2 = pos+1; *pos2; pos2++ )
|
||||
{
|
||||
if( *pos2 == L'\n' )
|
||||
break;
|
||||
|
||||
if( *pos2 != L'\t' && *pos2 !=L' ' )
|
||||
{
|
||||
is_empty = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( is_empty )
|
||||
{
|
||||
*(pos+1)=L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb_append( b, str );
|
||||
free( str );
|
||||
}
|
||||
@@ -215,6 +253,10 @@ static int builtin_bind( wchar_t **argv )
|
||||
L"set-mode", required_argument, 0, 'M'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -227,7 +269,7 @@ static int builtin_bind( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"M:",
|
||||
L"M:h",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -250,6 +292,10 @@ static int builtin_bind( wchar_t **argv )
|
||||
input_set_mode( woptarg );
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
@@ -337,7 +383,7 @@ static int builtin_block( wchar_t **argv )
|
||||
|
||||
return 1;
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case 'g':
|
||||
@@ -478,7 +524,7 @@ static int builtin_builtin( wchar_t **argv )
|
||||
|
||||
return 1;
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case 'n':
|
||||
@@ -701,6 +747,10 @@ static int builtin_functions( wchar_t **argv )
|
||||
L"all", no_argument, 0, 'a'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -713,7 +763,7 @@ static int builtin_functions( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"ed:na",
|
||||
L"ed:nah",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -749,6 +799,10 @@ static int builtin_functions( wchar_t **argv )
|
||||
show_hidden=1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
@@ -948,6 +1002,10 @@ static int builtin_function( wchar_t **argv )
|
||||
L"on-variable", required_argument, 0, 'v'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -960,7 +1018,7 @@ static int builtin_function( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"bd:s:j:p:v:",
|
||||
L"bd:s:j:p:v:h",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -1114,6 +1172,10 @@ static int builtin_function( wchar_t **argv )
|
||||
break;
|
||||
}
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
res = 1;
|
||||
@@ -1160,7 +1222,7 @@ static int builtin_function( wchar_t **argv )
|
||||
array_list_t names;
|
||||
int chars=0;
|
||||
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
const wchar_t *cfa = _( L"Current functions are: " );
|
||||
sb_append( sb_err, cfa );
|
||||
chars += wcslen( cfa );
|
||||
@@ -1258,7 +1320,7 @@ static int builtin_random( wchar_t **argv )
|
||||
return 1;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
break;
|
||||
|
||||
case '?':
|
||||
@@ -1368,6 +1430,10 @@ static int builtin_read( wchar_t **argv )
|
||||
L"command", required_argument, 0, 'c'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -1378,7 +1444,7 @@ static int builtin_read( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"xglUup:c:",
|
||||
L"xglUup:c:h",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -1419,6 +1485,10 @@ static int builtin_read( wchar_t **argv )
|
||||
commandline = woptarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case L'?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
@@ -1695,7 +1765,7 @@ static int builtin_status( wchar_t **argv )
|
||||
return 1;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case 'j':
|
||||
@@ -1849,7 +1919,7 @@ static int builtin_exit( wchar_t **argv )
|
||||
|
||||
default:
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Too many arguments\n" ),
|
||||
BUILTIN_ERR_TOO_MANY_ARGUMENTS,
|
||||
argv[0] );
|
||||
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
@@ -2259,309 +2329,6 @@ static int builtin_bg( wchar_t **argv )
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
/**
|
||||
Calculates the cpu usage (in percent) of the specified job.
|
||||
*/
|
||||
static int cpu_use( job_t *j )
|
||||
{
|
||||
double u=0;
|
||||
process_t *p;
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
struct timeval t;
|
||||
int jiffies;
|
||||
gettimeofday( &t, 0 );
|
||||
jiffies = proc_get_jiffies( p );
|
||||
|
||||
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
|
||||
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
|
||||
|
||||
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
|
||||
t1, t2, jiffies, p->last_jiffies );
|
||||
*/
|
||||
|
||||
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
|
||||
}
|
||||
return u*1000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Print information about the specified job
|
||||
*/
|
||||
static void builtin_jobs_print( job_t *j, int mode, int header )
|
||||
{
|
||||
process_t *p;
|
||||
switch( mode )
|
||||
{
|
||||
case JOBS_DEFAULT:
|
||||
{
|
||||
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Job\tGroup\t" ));
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
sb_append( sb_out, _( L"CPU\t" ) );
|
||||
#endif
|
||||
sb_append( sb_out, _( L"State\tCommand\n" ) );
|
||||
}
|
||||
|
||||
sb_printf( sb_out, L"%d\t%d\t", j->job_id, j->pgid );
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
sb_printf( sb_out, L"%d%%\t", cpu_use(j) );
|
||||
#endif
|
||||
sb_append2( sb_out,
|
||||
job_is_stopped(j)?_(L"stopped"):_(L"running"),
|
||||
L"\t",
|
||||
j->command,
|
||||
L"\n",
|
||||
(void *)0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_GROUP:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Group\n" ));
|
||||
}
|
||||
sb_printf( sb_out, L"%d\n", j->pgid );
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_PID:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Procces\n" ));
|
||||
}
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
sb_printf( sb_out, L"%d\n", p->pid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_COMMAND:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Command\n" ));
|
||||
}
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
sb_printf( sb_out, L"%ls\n", p->argv[0] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Builtin for printing running jobs
|
||||
*/
|
||||
static int builtin_jobs( wchar_t **argv )
|
||||
{
|
||||
int argc=0;
|
||||
int found=0;
|
||||
int mode=JOBS_DEFAULT;
|
||||
int print_last = 0;
|
||||
job_t *j;
|
||||
|
||||
argc = builtin_count_args( argv );
|
||||
woptind=0;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
const static struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{
|
||||
L"pid", no_argument, 0, 'p'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"command", no_argument, 0, 'c'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"group", no_argument, 0, 'g'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"last", no_argument, 0, 'l'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"pclg",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
switch( opt )
|
||||
{
|
||||
case 0:
|
||||
if(long_options[opt_index].flag != 0)
|
||||
break;
|
||||
sb_printf( sb_err,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name );
|
||||
|
||||
sb_append( sb_err,
|
||||
parser_current_line() );
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
case 'p':
|
||||
mode=JOBS_PRINT_PID;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
mode=JOBS_PRINT_COMMAND;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
mode=JOBS_PRINT_GROUP;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
{
|
||||
print_last = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case '?':
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Do not babble if not interactive
|
||||
*/
|
||||
if( builtin_out_redirect )
|
||||
{
|
||||
found=1;
|
||||
}
|
||||
|
||||
if( print_last )
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
for( j=first_job; j; j=j->next )
|
||||
{
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if( woptind < argc )
|
||||
{
|
||||
int i;
|
||||
|
||||
found = 1;
|
||||
|
||||
for( i=woptind; i<argc; i++ )
|
||||
{
|
||||
long pid;
|
||||
wchar_t *end;
|
||||
errno=0;
|
||||
pid=wcstol( argv[i], &end, 10 );
|
||||
if( errno || *end )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: '%ls' is not a job\n" ),
|
||||
argv[0],
|
||||
argv[i] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
j = job_get_from_pid( pid );
|
||||
|
||||
if( j && !job_is_completed( j ) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: No suitable job: %d\n" ),
|
||||
argv[0],
|
||||
pid );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( j= first_job; j; j=j->next )
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
sb_printf( sb_out,
|
||||
_( L"%ls: There are no jobs\n" ),
|
||||
argv[0] );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Builtin for looping over a list
|
||||
*/
|
||||
@@ -2590,7 +2357,7 @@ static int builtin_for( wchar_t **argv )
|
||||
else if (wcscmp( argv[2], L"in") != 0 )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: Second argument must be 'in'\n" ),
|
||||
BUILTIN_FOR_ERR_IN,
|
||||
argv[0] );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
}
|
||||
|
||||
26
builtin.h
26
builtin.h
@@ -57,6 +57,13 @@ enum
|
||||
*/
|
||||
#define BUILTIN_ERR_VARNAME_ZERO _( L"%ls: Variable name can not be the empty string\n" )
|
||||
|
||||
/**
|
||||
Error message when second argument to for isn't 'in'
|
||||
*/
|
||||
#define BUILTIN_FOR_ERR_IN _( L"%ls: Second argument must be 'in'\n" )
|
||||
|
||||
#define BUILTIN_ERR_TOO_MANY_ARGUMENTS _( L"%ls: Too many arguments\n" )
|
||||
|
||||
/**
|
||||
Stringbuffer used to represent standard output
|
||||
*/
|
||||
@@ -132,33 +139,42 @@ const wchar_t *builtin_get_desc( const wchar_t *b );
|
||||
int builtin_count_args( wchar_t **argv );
|
||||
|
||||
/**
|
||||
Print help for the specified builtin. If \c b is sb_err, also print the line information
|
||||
Print help for the specified builtin. If \c b is sb_err, also print
|
||||
the line information
|
||||
*/
|
||||
void builtin_print_help( wchar_t *cmd, string_buffer_t *b );
|
||||
|
||||
|
||||
/**
|
||||
The set builtin, used for setting variables. Defined in builtin_set.c.
|
||||
The set builtin, used for setting variables. Defined in
|
||||
builtin_set.c.
|
||||
*/
|
||||
int builtin_set(wchar_t **argv);
|
||||
|
||||
/**
|
||||
The commandline builtin, used for setting and getting the contents of the commandline. Defined in builtin_commandline.c.
|
||||
The commandline builtin, used for setting and getting the contents
|
||||
of the commandline. Defined in builtin_commandline.c.
|
||||
*/
|
||||
int builtin_commandline(wchar_t **argv);
|
||||
|
||||
/**
|
||||
The ulimit builtin, used for setting resource limits. Defined in builtin_ulimit.c.
|
||||
The ulimit builtin, used for setting resource limits. Defined in
|
||||
builtin_ulimit.c.
|
||||
*/
|
||||
int builtin_ulimit(wchar_t **argv);
|
||||
|
||||
/**
|
||||
The complete builtin. Used for specifying programmable
|
||||
tab-completions. Calls the functions in complete.c for any heavy
|
||||
lifting.
|
||||
lifting. Defined in builtin_complete.c
|
||||
*/
|
||||
int builtin_complete(wchar_t **argv);
|
||||
|
||||
/**
|
||||
The jobs builtin. Used fopr printing running jobs. Defined in builtin_jobs.c.
|
||||
*/
|
||||
int builtin_jobs(wchar_t **argv);
|
||||
|
||||
const wchar_t *builtin_complete_get_temporary_buffer();
|
||||
|
||||
/**
|
||||
|
||||
@@ -265,6 +265,10 @@ int builtin_commandline( wchar_t **argv )
|
||||
L"tokenize", no_argument, 0, 'o'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -275,7 +279,7 @@ int builtin_commandline( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"aijpctwfor",
|
||||
L"aijpctwforh",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -330,6 +334,10 @@ int builtin_commandline( wchar_t **argv )
|
||||
tokenize=1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case L'?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
|
||||
@@ -341,6 +341,10 @@ int builtin_complete( wchar_t **argv )
|
||||
L"do-complete", required_argument, 0, 'C'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -351,7 +355,7 @@ int builtin_complete( wchar_t **argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"a:c:p:s:l:o:d:frxeun:C:",
|
||||
L"a:c:p:s:l:o:d:frxeun:C:h",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -369,7 +373,7 @@ int builtin_complete( wchar_t **argv )
|
||||
sb_append( sb_err,
|
||||
parser_current_line() );
|
||||
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
|
||||
res = 1;
|
||||
@@ -431,10 +435,14 @@ int builtin_complete( wchar_t **argv )
|
||||
do_complete = woptarg?woptarg:reader_get_buffer();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
sb_append( sb_err,
|
||||
parser_current_line() );
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
res = 1;
|
||||
break;
|
||||
@@ -443,6 +451,42 @@ int builtin_complete( wchar_t **argv )
|
||||
|
||||
}
|
||||
|
||||
if( !res )
|
||||
{
|
||||
if( condition && wcslen( condition ) )
|
||||
{
|
||||
if( parser_test( condition, 0 ) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
L"%ls: Condition '%ls' contained a syntax error\n",
|
||||
argv[0],
|
||||
condition );
|
||||
|
||||
parser_test( condition, 1 );
|
||||
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !res )
|
||||
{
|
||||
if( comp && wcslen( comp ) )
|
||||
{
|
||||
if( parser_test_args( comp, 0 ) )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
L"%ls: Completion '%ls' contained a syntax error\n",
|
||||
argv[0],
|
||||
comp );
|
||||
|
||||
parser_test_args( comp, 1 );
|
||||
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !res )
|
||||
{
|
||||
if( do_complete )
|
||||
@@ -485,7 +529,7 @@ int builtin_complete( wchar_t **argv )
|
||||
argv[0] );
|
||||
sb_append( sb_err,
|
||||
parser_current_line() );
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
res = 1;
|
||||
}
|
||||
|
||||
349
builtin_jobs.c
Normal file
349
builtin_jobs.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/** \file builtin_jobs.c
|
||||
Functions for executing the jobs builtin.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "wutil.h"
|
||||
#include "builtin.h"
|
||||
#include "proc.h"
|
||||
#include "parser.h"
|
||||
#include "common.h"
|
||||
#include "wgetopt.h"
|
||||
#include "translate.h"
|
||||
|
||||
/**
|
||||
Print modes for the jobs builtin
|
||||
*/
|
||||
enum
|
||||
{
|
||||
JOBS_DEFAULT, /**< Print lots of general info */
|
||||
JOBS_PRINT_PID, /**< Print pid of each process in job */
|
||||
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
|
||||
JOBS_PRINT_GROUP, /**< Print group id of job */
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
/**
|
||||
Calculates the cpu usage (in percent) of the specified job.
|
||||
*/
|
||||
static int cpu_use( job_t *j )
|
||||
{
|
||||
double u=0;
|
||||
process_t *p;
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
struct timeval t;
|
||||
int jiffies;
|
||||
gettimeofday( &t, 0 );
|
||||
jiffies = proc_get_jiffies( p );
|
||||
|
||||
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
|
||||
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
|
||||
|
||||
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
|
||||
t1, t2, jiffies, p->last_jiffies );
|
||||
*/
|
||||
|
||||
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
|
||||
}
|
||||
return u*1000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Print information about the specified job
|
||||
*/
|
||||
static void builtin_jobs_print( job_t *j, int mode, int header )
|
||||
{
|
||||
process_t *p;
|
||||
switch( mode )
|
||||
{
|
||||
case JOBS_DEFAULT:
|
||||
{
|
||||
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Job\tGroup\t" ));
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
sb_append( sb_out, _( L"CPU\t" ) );
|
||||
#endif
|
||||
sb_append( sb_out, _( L"State\tCommand\n" ) );
|
||||
}
|
||||
|
||||
sb_printf( sb_out, L"%d\t%d\t", j->job_id, j->pgid );
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
sb_printf( sb_out, L"%d%%\t", cpu_use(j) );
|
||||
#endif
|
||||
sb_append2( sb_out,
|
||||
job_is_stopped(j)?_(L"stopped"):_(L"running"),
|
||||
L"\t",
|
||||
j->command,
|
||||
L"\n",
|
||||
(void *)0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_GROUP:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Group\n" ));
|
||||
}
|
||||
sb_printf( sb_out, L"%d\n", j->pgid );
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_PID:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Procces\n" ));
|
||||
}
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
sb_printf( sb_out, L"%d\n", p->pid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_COMMAND:
|
||||
{
|
||||
if( header )
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
sb_append( sb_out, _( L"Command\n" ));
|
||||
}
|
||||
|
||||
for( p=j->first_process; p; p=p->next )
|
||||
{
|
||||
sb_printf( sb_out, L"%ls\n", p->argv[0] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int builtin_jobs( wchar_t **argv )
|
||||
{
|
||||
int argc=0;
|
||||
int found=0;
|
||||
int mode=JOBS_DEFAULT;
|
||||
int print_last = 0;
|
||||
job_t *j;
|
||||
|
||||
argc = builtin_count_args( argv );
|
||||
woptind=0;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
const static struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{
|
||||
L"pid", no_argument, 0, 'p'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"command", no_argument, 0, 'c'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"group", no_argument, 0, 'g'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"last", no_argument, 0, 'l'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"pclgh",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
switch( opt )
|
||||
{
|
||||
case 0:
|
||||
if(long_options[opt_index].flag != 0)
|
||||
break;
|
||||
sb_printf( sb_err,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name );
|
||||
|
||||
sb_append( sb_err,
|
||||
parser_current_line() );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
case 'p':
|
||||
mode=JOBS_PRINT_PID;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
mode=JOBS_PRINT_COMMAND;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
mode=JOBS_PRINT_GROUP;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
{
|
||||
print_last = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Do not babble if not interactive
|
||||
*/
|
||||
if( builtin_out_redirect )
|
||||
{
|
||||
found=1;
|
||||
}
|
||||
|
||||
if( print_last )
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
for( j=first_job; j; j=j->next )
|
||||
{
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if( woptind < argc )
|
||||
{
|
||||
int i;
|
||||
|
||||
found = 1;
|
||||
|
||||
for( i=woptind; i<argc; i++ )
|
||||
{
|
||||
long pid;
|
||||
wchar_t *end;
|
||||
errno=0;
|
||||
pid=wcstol( argv[i], &end, 10 );
|
||||
if( errno || *end )
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: '%ls' is not a job\n" ),
|
||||
argv[0],
|
||||
argv[i] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
j = job_get_from_pid( pid );
|
||||
|
||||
if( j && !job_is_completed( j ) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_printf( sb_err,
|
||||
_( L"%ls: No suitable job: %d\n" ),
|
||||
argv[0],
|
||||
pid );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( j= first_job; j; j=j->next )
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
if( j->constructed && !job_is_completed(j) )
|
||||
{
|
||||
builtin_jobs_print( j, mode, !found );
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
sb_printf( sb_out,
|
||||
_( L"%ls: There are no jobs\n" ),
|
||||
argv[0] );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -373,35 +373,47 @@ int builtin_set( wchar_t **argv )
|
||||
{
|
||||
{
|
||||
L"export", no_argument, 0, 'x'
|
||||
},
|
||||
}
|
||||
,
|
||||
{
|
||||
L"global", no_argument, 0, 'g'
|
||||
},
|
||||
}
|
||||
,
|
||||
{
|
||||
L"local", no_argument, 0, 'l'
|
||||
},
|
||||
}
|
||||
,
|
||||
{
|
||||
L"erase", no_argument, 0, 'e'
|
||||
},
|
||||
}
|
||||
,
|
||||
{
|
||||
L"names", no_argument, 0, 'n'
|
||||
} ,
|
||||
}
|
||||
,
|
||||
{
|
||||
L"unexport", no_argument, 0, 'u'
|
||||
} ,
|
||||
}
|
||||
,
|
||||
{
|
||||
L"universal", no_argument, 0, 'U'
|
||||
} ,
|
||||
}
|
||||
,
|
||||
{
|
||||
L"query", no_argument, 0, 'q'
|
||||
} ,
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
const wchar_t *short_options = L"+xglenuUq";
|
||||
const wchar_t *short_options = L"+xglenuUqh";
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
@@ -438,32 +450,47 @@ int builtin_set( wchar_t **argv )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
erase = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
list = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
export = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
local = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
global = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unexport = 1;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
universal = 1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
query = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -485,7 +512,7 @@ int builtin_set( wchar_t **argv )
|
||||
argv[0],
|
||||
parser_current_line() );
|
||||
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -498,7 +525,7 @@ int builtin_set( wchar_t **argv )
|
||||
argv[0],
|
||||
parser_current_line() );
|
||||
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -511,7 +538,7 @@ int builtin_set( wchar_t **argv )
|
||||
BUILTIN_ERR_GLOCAL,
|
||||
argv[0],
|
||||
parser_current_line() );
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -524,7 +551,7 @@ int builtin_set( wchar_t **argv )
|
||||
BUILTIN_ERR_EXPUNEXP,
|
||||
argv[0],
|
||||
parser_current_line() );
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -564,7 +591,7 @@ int builtin_set( wchar_t **argv )
|
||||
argv[0],
|
||||
parser_current_line() );
|
||||
|
||||
// builtin_print_help( argv[0], sb_err );
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
retcode = 1;
|
||||
}
|
||||
else
|
||||
@@ -655,7 +682,7 @@ int builtin_set( wchar_t **argv )
|
||||
array_list_t result;
|
||||
al_init(&result);
|
||||
|
||||
expand_variable_array( env_get(dest), &result );
|
||||
tokenize_variable_array( env_get(dest), &result );
|
||||
if( erase )
|
||||
{
|
||||
erase_values(&result, &indexes);
|
||||
|
||||
@@ -63,13 +63,13 @@ const static struct resource_t resource_arr[] =
|
||||
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
|
||||
}
|
||||
,
|
||||
#if HAVE_RLIMIT_MEMLOCK
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{
|
||||
RLIMIT_MEMLOCK, L"Maximum size that may be locked into memory", L'l', 1024
|
||||
}
|
||||
,
|
||||
#endif
|
||||
#if HAVE_RLIMIT_RSS
|
||||
#ifdef RLIMIT_RSS
|
||||
{
|
||||
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
|
||||
}
|
||||
@@ -87,13 +87,13 @@ const static struct resource_t resource_arr[] =
|
||||
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
|
||||
}
|
||||
,
|
||||
#if HAVE_RLIMIT_NPROC
|
||||
#ifdef RLIMIT_NPROC
|
||||
{
|
||||
RLIMIT_NPROC, L"Maximum number of processes available to a single user", L'u', 1
|
||||
}
|
||||
,
|
||||
#endif
|
||||
#if HAVE_RLIMIT_AS
|
||||
#ifdef RLIMIT_AS
|
||||
{
|
||||
RLIMIT_AS, L"Maximum amount of virtual memory available to the shell", L'v', 1024
|
||||
}
|
||||
@@ -326,6 +326,10 @@ int builtin_ulimit( wchar_t ** argv )
|
||||
L"virtual-memory-size", no_argument, 0, 'v'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
@@ -337,7 +341,7 @@ int builtin_ulimit( wchar_t ** argv )
|
||||
|
||||
int opt = wgetopt_long( argc,
|
||||
argv,
|
||||
L"aHScdflmnptuv",
|
||||
L"aHScdflmnptuvh",
|
||||
long_options,
|
||||
&opt_index );
|
||||
if( opt == -1 )
|
||||
@@ -379,13 +383,13 @@ int builtin_ulimit( wchar_t ** argv )
|
||||
case L'f':
|
||||
what=RLIMIT_FSIZE;
|
||||
break;
|
||||
#if HAVE_RLIMIT_MEMLOCK
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
case L'l':
|
||||
what=RLIMIT_MEMLOCK;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if HAVE_RLIMIT_RSS
|
||||
#ifdef RLIMIT_RSS
|
||||
case L'm':
|
||||
what=RLIMIT_RSS;
|
||||
break;
|
||||
@@ -403,18 +407,22 @@ int builtin_ulimit( wchar_t ** argv )
|
||||
what=RLIMIT_CPU;
|
||||
break;
|
||||
|
||||
#if HAVE_RLIMIT_NPROC
|
||||
#ifdef RLIMIT_NPROC
|
||||
case L'u':
|
||||
what=RLIMIT_NPROC;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if HAVE_RLIMIT_AS
|
||||
#ifdef RLIMIT_AS
|
||||
case L'v':
|
||||
what=RLIMIT_AS;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case L'h':
|
||||
builtin_print_help( argv[0], sb_out );
|
||||
return 0;
|
||||
|
||||
case L'?':
|
||||
builtin_print_help( argv[0], sb_err );
|
||||
return 1;
|
||||
|
||||
51
common.c
51
common.c
@@ -67,21 +67,6 @@ parts of fish.
|
||||
*/
|
||||
#define LOCKPOLLINTERVAL 10
|
||||
|
||||
/**
|
||||
Highest legal ascii value
|
||||
*/
|
||||
#define ASCII_MAX 127u
|
||||
|
||||
/**
|
||||
Highest legal 16-bit unicode value
|
||||
*/
|
||||
#define UCS2_MAX 0xffffu
|
||||
|
||||
/**
|
||||
Highest legal byte value
|
||||
*/
|
||||
#define BYTE_MAX 0xffu
|
||||
|
||||
struct termios shell_modes;
|
||||
|
||||
int error_max=1;
|
||||
@@ -562,9 +547,10 @@ void debug( int level, const wchar_t *msg, ... )
|
||||
|
||||
sb_init( &sb );
|
||||
sb_init( &sb2 );
|
||||
va_start( va, msg );
|
||||
|
||||
|
||||
sb_printf( &sb, L"%ls: ", program_name );
|
||||
|
||||
va_start( va, msg );
|
||||
sb_vprintf( &sb, msg, va );
|
||||
va_end( va );
|
||||
|
||||
@@ -596,7 +582,7 @@ void write_screen( const wchar_t *msg, string_buffer_t *buff )
|
||||
*/
|
||||
while( *pos && ( !wcschr( L" \n\r\t", *pos ) ) )
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
Check is token is wider than one line.
|
||||
If so we mark it as an overflow and break the token.
|
||||
@@ -621,7 +607,7 @@ void write_screen( const wchar_t *msg, string_buffer_t *buff )
|
||||
else if( overflow )
|
||||
{
|
||||
/*
|
||||
In case of overflow, we print a newline, except if we alreade are at position 0
|
||||
In case of overflow, we print a newline, except if we already are at position 0
|
||||
*/
|
||||
wchar_t *token = wcsndup( start, pos-start );
|
||||
if( line_width != 0 )
|
||||
@@ -645,6 +631,7 @@ void write_screen( const wchar_t *msg, string_buffer_t *buff )
|
||||
free( token );
|
||||
line_width += (line_width!=0?1:0) + tok_width;
|
||||
}
|
||||
|
||||
/*
|
||||
Break on end of string
|
||||
*/
|
||||
@@ -1418,3 +1405,29 @@ int common_get_height()
|
||||
return termsize.ws_row;
|
||||
}
|
||||
|
||||
void tokenize_variable_array( const wchar_t *val, array_list_t *out )
|
||||
{
|
||||
if( val )
|
||||
{
|
||||
wchar_t *cpy = wcsdup( val );
|
||||
wchar_t *pos, *start;
|
||||
|
||||
if( !cpy )
|
||||
{
|
||||
die_mem();
|
||||
}
|
||||
|
||||
for( start=pos=cpy; *pos; pos++ )
|
||||
{
|
||||
if( *pos == ARRAY_SEP )
|
||||
{
|
||||
*pos=0;
|
||||
al_push( out, start==cpy?cpy:wcsdup(start) );
|
||||
start=pos+1;
|
||||
}
|
||||
}
|
||||
al_push( out, start==cpy?cpy:wcsdup(start) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
36
common.h
36
common.h
@@ -20,22 +20,26 @@
|
||||
*/
|
||||
#define MAX_UTF8_BYTES 6
|
||||
|
||||
/**
|
||||
Color code for set_color. Does not update the color.
|
||||
*/
|
||||
|
||||
#define FISH_COLOR_IGNORE -1
|
||||
|
||||
/**
|
||||
Color code for set_color. Sets the default color.
|
||||
*/
|
||||
#define FISH_COLOR_RESET -2
|
||||
|
||||
/**
|
||||
This is in the unicode private use area.
|
||||
*/
|
||||
#define ENCODE_DIRECT_BASE 0xf100
|
||||
|
||||
/**
|
||||
Highest legal ascii value
|
||||
*/
|
||||
#define ASCII_MAX 127u
|
||||
|
||||
/**
|
||||
Highest legal 16-bit unicode value
|
||||
*/
|
||||
#define UCS2_MAX 0xffffu
|
||||
|
||||
/**
|
||||
Highest legal byte value
|
||||
*/
|
||||
#define BYTE_MAX 0xffu
|
||||
|
||||
/**
|
||||
Save the shell mode on startup so we can restore them on exit
|
||||
*/
|
||||
@@ -292,6 +296,16 @@ void common_handle_winch( int signal );
|
||||
*/
|
||||
void write_screen( const wchar_t *msg, string_buffer_t *buff );
|
||||
|
||||
/**
|
||||
Tokenize the specified string into the specified array_list_t.
|
||||
Each new element is allocated using malloc and must be freed by the
|
||||
caller.
|
||||
|
||||
\param val the input string. The contents of this string is not changed.
|
||||
\param out the list in which to place the elements.
|
||||
*/
|
||||
void tokenize_variable_array( const wchar_t *val, array_list_t *out );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
27
complete.c
27
complete.c
@@ -2023,9 +2023,28 @@ void complete( const wchar_t *cmd,
|
||||
current_token = wcsndup( begin, cursor_pos-(begin-cmd) );
|
||||
|
||||
prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L"");
|
||||
|
||||
|
||||
// fwprintf( stderr, L"on_command: %d, %ls %ls\n", on_command, current_compmand, current_token );
|
||||
|
||||
if( !had_cmd )
|
||||
{
|
||||
on_command=1;
|
||||
}
|
||||
|
||||
if( !current_token )
|
||||
{
|
||||
current_token = wcsdup(L"");
|
||||
}
|
||||
|
||||
if( !current_command )
|
||||
{
|
||||
current_command = wcsdup(L"");
|
||||
}
|
||||
|
||||
if( !prev_token )
|
||||
{
|
||||
prev_token = wcsdup(L"");
|
||||
}
|
||||
|
||||
if( current_token && current_command && prev_token )
|
||||
{
|
||||
if( on_command )
|
||||
@@ -2045,14 +2064,14 @@ void complete( const wchar_t *cmd,
|
||||
*/
|
||||
|
||||
int do_file;
|
||||
|
||||
|
||||
do_file = complete_param( current_command, prev_token, current_token, comp );
|
||||
complete_param_expand( current_token, comp, do_file );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
free( current_token );
|
||||
free( current_command );
|
||||
free( prev_token );
|
||||
|
||||
49
configure.ac
49
configure.ac
@@ -1,5 +1,5 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(fish,1.21.7,fish-users@lists.sf.net)
|
||||
AC_INIT(fish,1.21.8,fish-users@lists.sf.net)
|
||||
|
||||
# If needed, run autoconf to regenerate the configure file
|
||||
AC_MSG_CHECKING([if autoconf needs to be run])
|
||||
@@ -326,53 +326,6 @@ if test "$ac_cv_func_fwprintf" = yes; then
|
||||
|
||||
fi
|
||||
|
||||
# Check for RLIMIT_NPROC in sys/resource.h.
|
||||
AC_MSG_CHECKING([for RLIMIT_NPROC in sys/resource.h])
|
||||
AC_TRY_COMPILE([#include <sys/resource.h>],
|
||||
[int tmp; tmp=RLIMIT_NPROC;], have_rlimit_as=yes, have_rlimit_as=no)
|
||||
if test "$have_rlimit_as" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_RLIMIT_NPROC], [1],
|
||||
[Define to 1 if HAVE_RLIMIT_NPROC is defined in <sys/resource.h>.])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for RLIMIT_AS in sys/resource.h.
|
||||
AC_MSG_CHECKING([for RLIMIT_AS in sys/resource.h])
|
||||
AC_TRY_COMPILE([#include <sys/resource.h>],
|
||||
[int tmp; tmp=RLIMIT_AS;], have_rlimit_as=yes, have_rlimit_as=no)
|
||||
if test "$have_rlimit_as" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_RLIMIT_AS], [1],
|
||||
[Define to 1 if HAVE_RLIMIT_AS is defined in <sys/resource.h>.])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for RLIMIT_MEMLOCK in sys/resource.h.
|
||||
AC_MSG_CHECKING([for RLIMIT_MEMLOCK in sys/resource.h])
|
||||
AC_TRY_COMPILE([#include <sys/resource.h>],
|
||||
[int tmp; tmp=RLIMIT_MEMLOCK;], have_rlimit_as=yes, have_rlimit_as=no)
|
||||
if test "$have_rlimit_as" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_RLIMIT_MEMLOCK], [1],
|
||||
[Define to 1 if HAVE_RLIMIT_MEMLOCK is defined in <sys/resource.h>.])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for RLIMIT_RSS in sys/resource.h.
|
||||
AC_MSG_CHECKING([for RLIMIT_RSS in sys/resource.h])
|
||||
AC_TRY_COMPILE([#include <sys/resource.h>],
|
||||
[int tmp; tmp=RLIMIT_RSS;], have_rlimit_as=yes, have_rlimit_as=no)
|
||||
if test "$have_rlimit_as" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_RLIMIT_RSS], [1],
|
||||
[Define to 1 if HAVE_RLIMIT_RSS is defined in <sys/resource.h>.])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for _nl_msg_cat_cntr symbol
|
||||
AC_MSG_CHECKING([for _nl_msg_cat_cntr symbol])
|
||||
|
||||
@@ -49,12 +49,12 @@ has to be used.
|
||||
Here is a list of some useful commands:
|
||||
|
||||
- \c cd, change the current directory
|
||||
- \c ls, list the contents of a directory
|
||||
- \c man, print a manual page
|
||||
- \c mv, move files
|
||||
- \c ls, list files and directories
|
||||
- \c man, display a manual page on the screen
|
||||
- \c mv, move (rename) files
|
||||
- \c cp, copy files
|
||||
- \c open, open files with the default application associated with each filetype
|
||||
- \c less, read the contents of files
|
||||
- \c less, list the contents of files
|
||||
|
||||
Commands and parameters are separated by the space character
|
||||
( ). Every command ends with either a newline (i.e. by pressing
|
||||
@@ -68,10 +68,10 @@ and directories in the current working directory, but by using the \c
|
||||
-l switch, the behaviour of ls is changed to not only display the
|
||||
filename, but also the size, permissions, owner and modification time
|
||||
of each file. Switches differ between commands and are documented in
|
||||
the manual page for each command. Some switches are very common
|
||||
though, for example '--help' will usually display a help text, '-i'
|
||||
will often turn on interactive prompting before taking action, while
|
||||
'-f' will turn it off.
|
||||
the manual page for each command. Some switches are common to most
|
||||
command though, for example '--help' will usually display a help text,
|
||||
'-i' will often turn on interactive prompting before taking action,
|
||||
while '-f' will turn it off.
|
||||
|
||||
\subsection quotes Quotes
|
||||
|
||||
@@ -116,6 +116,7 @@ these characters, so called escape sequences are provided. These are:
|
||||
- <code>'\\*'</code>, escapes the star character
|
||||
- <code>'\\?'</code>, escapes the question mark character
|
||||
- <code>'\\~'</code>, escapes the tilde character
|
||||
- <code>'\\%'</code>, escapes the percent character
|
||||
- <code>'\\#'</code>, escapes the hash character
|
||||
- <code>'\\('</code>, escapes the left parenthesis character
|
||||
- <code>'\\)'</code>, escapes the right parenthesis character
|
||||
@@ -540,6 +541,7 @@ a string is expanded into a process id. The following expansions are
|
||||
performed:
|
||||
|
||||
- If the string is the entire word \c self, the shells pid is the result
|
||||
- When inside a command substitution, if the string is the entire word \c caller, the job number (not the pid) of the job the created the command substitution is the result
|
||||
- Otherwise, if the string is the id of a job, the result is the process
|
||||
group id of the job.
|
||||
- Otherwise, if any child processes match the specified string, their
|
||||
@@ -752,7 +754,8 @@ certain environment variables.
|
||||
|
||||
- \c BROWSER, which is the users preferred web browser. If this variable is set, fish will use the specified browser instead of the system default browser to display the fish documentation.
|
||||
- \c CDPATH, which is an array of directories in which to search for the new directory for the \c cd builtin.
|
||||
- \c fish_color_normal, \c fish_color_command, \c fish_color_substitution, \c fish_color_redirection, \c fish_color_end, \c fish_color_error, \c fish_color_param, \c fish_color_comment, \c fish_color_match, \c fish_color_search_match, \c fish_color_cwd, \c fish_pager_color_prefix, \c fish_pager_color_completion, \c fish_pager_color_description and \c fish_pager_color_progress are used to change the color of various elements in \c fish. These variables are universal, i.e. when changing them, their new value will be used by all running fish sessions. The new value will also be retained when restarting fish.
|
||||
- A large number of variable starting with the prefixes \c fish_color and \c fish_pager_color. See <a href='#variables-color'>Variables for changing highlighting colors</a> for more information.
|
||||
- \c LANG, \c LC_ALL, \c LC_COLLATE, \c LC_CTYPE, \c LC_MESSAGES, \c LC_MONETARY, \c LC_NUMERIC and \c LC_TIME set the language option for the shell and subprograms. See the section <a href='#variables-locale'>Locale variables</a> for more information.
|
||||
- \c PATH, which is an array of directories in which to search for commands
|
||||
- \c umask, which is the current file creation mask. The preferred way to change the umask variable is through the <a href="commands.html#umask">umask shellscript function</a>. An attempt to set umask to an invalid value will always fail.
|
||||
|
||||
@@ -767,7 +770,6 @@ values of most of these variables.
|
||||
- \c PWD, which is the current working directory.
|
||||
- \c status, which is the exit status of the last foreground job to exit. If a job contains pipelines, the status of the last command in the pipeline is the status for the job.
|
||||
- \c USER, which is the username. This variable can only be changed by the root user.
|
||||
- \c LANG, \c LC_ALL, \c LC_COLLATE, \c LC_CTYPE, \c LC_MESSAGES, \c LC_MONETARY, \c LC_NUMERIC and \c LC_TIME set the language option for the shell and subprograms. See the section <a href='#variables-locale'>Locale variables</a> for more information.
|
||||
|
||||
Variables whose name are in uppercase are exported to the commands
|
||||
started by fish, those in lowercase are not exported. This rule is not
|
||||
@@ -776,6 +778,45 @@ distinguish between exported and unexported variables. \c fish also
|
||||
uses several variables internally. Such variables are prefixed with
|
||||
the string __FISH or __fish. These should be ignored by the user.
|
||||
|
||||
\subsection variables-color Variables for changing highlighting colors
|
||||
|
||||
The colors used by fish for syntax highlighting can be configured by
|
||||
changing the values of a various variables. The value of these
|
||||
variables can be one of the colors accepted by the <a
|
||||
href='commands.html#set_color'>\c set_color</a> command. The \c --bold
|
||||
or \c -b switches accepted by \c set_color are also accepted.
|
||||
|
||||
The following variables are available to change the highligting colors
|
||||
in fish:
|
||||
|
||||
- \c fish_color_normal, the default color
|
||||
- \c fish_color_command, the color for commands
|
||||
- \c fish_color_quote, the color for quoted blocks of text
|
||||
- \c fish_color_redirection, the color for IO redirections
|
||||
- \c fish_color_end, the color for process separators like ';' and '&'
|
||||
- \c fish_color_error, the color used to highlight potential errors
|
||||
- \c fish_color_param, the color for regular command parameters
|
||||
- \c fish_color_comment, the color used for code comments
|
||||
- \c fish_color_match, the color used to highlight matching parenthesis
|
||||
- \c fish_color_search_match, the color used to highlight history search matches
|
||||
- \c fish_color_operator, the color for parameter expansion operators like '*' and '~'
|
||||
- \c fish_color_escape, the color used to highlight character escapes like '\\n' and '\\x70'
|
||||
- \c fish_color_cwd, the color used for the current working directory in the default prompt
|
||||
|
||||
Additionally, the following variables are available to change the
|
||||
highlighting in the completion pager:
|
||||
|
||||
- \c fish_pager_color_prefix, the color of the prefix string, i.e. the string that is to be completed
|
||||
- \c fish_pager_color_completion, the color of the completion itself
|
||||
- \c fish_pager_color_description, the color of the completion description
|
||||
- \c fish_pager_color_progress, the color of the progress bar at the bottom left corner
|
||||
|
||||
Example:
|
||||
|
||||
To make errors highlighted and red, use:
|
||||
|
||||
<code>set fish_color_error red --bold</code>D
|
||||
|
||||
\subsection variables-locale Locale variables
|
||||
|
||||
The most common way to set the locale to use a command like 'set -x
|
||||
@@ -1197,12 +1238,9 @@ compress, wine, xmms, dig, wine, batch, cron,
|
||||
g++, javac, java, gcj, lpr, doxygen, whois, find)
|
||||
- Undo support
|
||||
- Check keybinding commands for output - if nothing has happened, don't repaint to reduce flicker
|
||||
- The jobs builtin should be able to give information on a specific job, such as the pids of the processes in the job
|
||||
- Syntax highlighting should mark cd to non-existing directories as an error
|
||||
- wait shellscript
|
||||
- Support for the screen clipboard
|
||||
- The -a string sent to complete should be validated
|
||||
- Fish should detect improper variable expansion when validating, e.g. strings such as 'foo$' and 'a${}' should be detected as invalid
|
||||
|
||||
|
||||
\subsection todo-possible Possible features
|
||||
@@ -1220,7 +1258,6 @@ g++, javac, java, gcj, lpr, doxygen, whois, find)
|
||||
- Inclusion guards for the init files to make them evaluate only once, even if the user has installed fish both in /etc and in $HOME
|
||||
- Do not actually load/parse .fish_history, only mmap it and use some clever string handling. Should save ~150 kB of memory permanently, but is very hard to implement.
|
||||
- command specific wildcarding (use case * instead of case '*', etc.)
|
||||
- show the whole list of commands on using tab on an empty commandline
|
||||
- Map variables. (export only the values. When expanding with no key specified, expand to all values.)
|
||||
- Descriptions for variables using 'set -d'.
|
||||
- Parse errors should when possible honor IO redirections
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
\subsection set-synopsis Synopsis
|
||||
<code>set [OPTIONS] [VARIABLE_NAME [VALUES...]]</code>
|
||||
|
||||
or
|
||||
|
||||
<code>set [OPTIONS] [VARIABLE_NAME[INDICES]... [VALUES...]]</code>
|
||||
|
||||
The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_NAME</code> the values <code>VALUES...</code>.
|
||||
|
||||
\subsection set-description Description
|
||||
@@ -29,7 +33,9 @@ elements, it will become an array with zero elements.
|
||||
|
||||
If the variable name is one or more array elements, such as
|
||||
<code>PATH[1 3 7]</code>, only those array elements specified will be
|
||||
changed.
|
||||
changed. When array indices are specified to set, multiple arguments
|
||||
may be used to specify additional indexes, e.g. <code>set PATH[1]
|
||||
PATH[4] /bin /sbin</code>.
|
||||
|
||||
The set command requires all switch arguments to come before any
|
||||
non-switch arguments. For example, <code>set flags -l</code> will have
|
||||
|
||||
24
env.c
24
env.c
@@ -396,7 +396,7 @@ static void setup_path()
|
||||
al_init( &l );
|
||||
|
||||
if( path )
|
||||
expand_variable_array( path, &l );
|
||||
tokenize_variable_array( path, &l );
|
||||
|
||||
for( j=0; path_el[j]; j++ )
|
||||
{
|
||||
@@ -438,7 +438,7 @@ static void setup_path()
|
||||
al_foreach( &l, (void (*)(const void *))&free );
|
||||
path = env_get( L"PATH" );
|
||||
al_truncate( &l, 0 );
|
||||
expand_variable_array( path, &l );
|
||||
tokenize_variable_array( path, &l );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,6 +797,7 @@ int env_set( const wchar_t *key,
|
||||
|
||||
al_init( &ev.arguments );
|
||||
al_push( &ev.arguments, L"VARIABLE" );
|
||||
al_push( &ev.arguments, L"SET" );
|
||||
al_push( &ev.arguments, key );
|
||||
|
||||
// debug( 1, L"env_set: fire events on variable %ls", key );
|
||||
@@ -817,6 +818,8 @@ int env_set( const wchar_t *key,
|
||||
/**
|
||||
Attempt to remove/free the specified key/value pair from the
|
||||
specified hash table.
|
||||
|
||||
\return zero if the variable was not found, non-zero otherwise
|
||||
*/
|
||||
static int try_remove( env_node_t *n,
|
||||
const wchar_t *key )
|
||||
@@ -862,7 +865,22 @@ void env_remove( const wchar_t *key, int var_mode )
|
||||
return;
|
||||
}
|
||||
|
||||
if( !try_remove( top, key ) )
|
||||
if( try_remove( top, key ) )
|
||||
{
|
||||
event_t ev;
|
||||
|
||||
ev.type=EVENT_VARIABLE;
|
||||
ev.param1.variable=key;
|
||||
ev.function_name=0;
|
||||
|
||||
al_init( &ev.arguments );
|
||||
al_push( &ev.arguments, L"VARIABLE" );
|
||||
al_push( &ev.arguments, L"ERASE" );
|
||||
al_push( &ev.arguments, key );
|
||||
event_fire( &ev );
|
||||
al_destroy( &ev.arguments );
|
||||
}
|
||||
else
|
||||
{
|
||||
env_universal_remove( key );
|
||||
}
|
||||
|
||||
@@ -68,8 +68,11 @@ end
|
||||
set_default fish_color_normal normal
|
||||
set_default fish_color_command green
|
||||
set_default fish_color_redirection normal
|
||||
set_default fish_color_comment brown
|
||||
set_default fish_color_error red
|
||||
set_default fish_color_comment red
|
||||
set_default fish_color_error red --bold
|
||||
set_default fish_color_escape cyan
|
||||
set_default fish_color_operator cyan
|
||||
set_default fish_color_quote brown
|
||||
|
||||
set_default fish_color_cwd green
|
||||
|
||||
|
||||
142
expand.c
142
expand.c
@@ -76,27 +76,6 @@ parameter expansion.
|
||||
*/
|
||||
#define COMPLETE_LAST_DESC _( L"Last background job")
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_DESC _( L"The '$' character begins a variable name. The character '%lc', which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_NULL_DESC _( L"The '$' begins a variable name. It was given at the end of an argument. Variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_BRACKET_DESC _( L"Did you mean {$VARIABLE}? The '$' character begins a variable name. A bracket, which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'." )
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_PARAN_DESC _( L"Did you mean (COMMAND)? In fish, the '$' character is only used for accessing variables. To learn more about command substitution in fish, type 'help expand-command-substitution'.")
|
||||
|
||||
|
||||
/**
|
||||
String in process expansion denoting ourself
|
||||
*/
|
||||
@@ -117,15 +96,7 @@ parameter expansion.
|
||||
*/
|
||||
#define UNCLEAN L"$*?\\\"'({})"
|
||||
|
||||
/**
|
||||
Test if the specified argument is clean, i.e. it does not contain
|
||||
any tokens which need to be expanded or otherwise altered. Clean
|
||||
strings can be passed through expand_string and expand_one without
|
||||
changing them. About 90% of all strings are clean, so skipping
|
||||
expansion on them actually does save a small amount of time, since
|
||||
it avoids multiple memory allocations during the expansion process.
|
||||
*/
|
||||
static int is_clean( const wchar_t *in )
|
||||
int expand_is_clean( const wchar_t *in )
|
||||
{
|
||||
|
||||
const wchar_t * str = in;
|
||||
@@ -159,32 +130,6 @@ static wchar_t *expand_var( wchar_t *in )
|
||||
return env_get( in );
|
||||
}
|
||||
|
||||
void expand_variable_array( const wchar_t *val, array_list_t *out )
|
||||
{
|
||||
if( val )
|
||||
{
|
||||
wchar_t *cpy = wcsdup( val );
|
||||
wchar_t *pos, *start;
|
||||
|
||||
if( !cpy )
|
||||
{
|
||||
die_mem();
|
||||
}
|
||||
|
||||
for( start=pos=cpy; *pos; pos++ )
|
||||
{
|
||||
if( *pos == ARRAY_SEP )
|
||||
{
|
||||
*pos=0;
|
||||
al_push( out, start==cpy?cpy:wcsdup(start) );
|
||||
start=pos+1;
|
||||
}
|
||||
}
|
||||
al_push( out, start==cpy?cpy:wcsdup(start) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Test if the specified string does not contain character which can
|
||||
not be used inside a quoted string.
|
||||
@@ -217,7 +162,7 @@ wchar_t *expand_escape_variable( const wchar_t *in )
|
||||
string_buffer_t buff;
|
||||
|
||||
al_init( &l );
|
||||
expand_variable_array( in, &l );
|
||||
tokenize_variable_array( in, &l );
|
||||
sb_init( &buff );
|
||||
|
||||
switch( al_get_count( &l) )
|
||||
@@ -225,7 +170,7 @@ wchar_t *expand_escape_variable( const wchar_t *in )
|
||||
case 0:
|
||||
sb_append( &buff, L"''");
|
||||
break;
|
||||
|
||||
|
||||
case 1:
|
||||
{
|
||||
wchar_t *el = (wchar_t *)al_get( &l, 0 );
|
||||
@@ -281,28 +226,19 @@ wchar_t *expand_escape_variable( const wchar_t *in )
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Tests if all characters in the string are numeric
|
||||
*/
|
||||
static int isnumeric( const char *n )
|
||||
{
|
||||
if( *n == '\0' )
|
||||
return 1;
|
||||
if( *n < '0' || *n > '9' )
|
||||
return 0;
|
||||
return isnumeric( n+1 );
|
||||
}
|
||||
|
||||
/**
|
||||
Tests if all characters in the wide string are numeric
|
||||
*/
|
||||
static int iswnumeric( const wchar_t *n )
|
||||
{
|
||||
if( *n == L'\0' )
|
||||
return 1;
|
||||
if( *n < L'0' || *n > L'9' )
|
||||
return 0;
|
||||
return iswnumeric( n+1 );
|
||||
for( ; *n; n++ )
|
||||
{
|
||||
if( *n < L'0' || *n > L'9' )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,9 +313,9 @@ static int find_process( const wchar_t *proc,
|
||||
array_list_t *out )
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *next;
|
||||
char *pdir_name;
|
||||
char *pfile_name;
|
||||
struct wdirent *next;
|
||||
wchar_t *pdir_name;
|
||||
wchar_t *pfile_name;
|
||||
wchar_t *cmd=0;
|
||||
int sz=0;
|
||||
int found = 0;
|
||||
@@ -515,20 +451,20 @@ static int find_process( const wchar_t *proc,
|
||||
return 1;
|
||||
}
|
||||
|
||||
pdir_name = malloc( 256 );
|
||||
pfile_name = malloc( 64 );
|
||||
strcpy( pdir_name, "/proc/" );
|
||||
|
||||
while( (next=readdir(dir))!=0 )
|
||||
pdir_name = malloc( sizeof(wchar_t)*256 );
|
||||
pfile_name = malloc( sizeof(wchar_t)*64 );
|
||||
wcscpy( pdir_name, L"/proc/" );
|
||||
|
||||
while( (next=wreaddir(dir))!=0 )
|
||||
{
|
||||
char *name = next->d_name;
|
||||
wchar_t *name = next->d_name;
|
||||
struct stat buf;
|
||||
|
||||
if( !isnumeric( name ) )
|
||||
if( !iswnumeric( name ) )
|
||||
continue;
|
||||
|
||||
strcpy( pdir_name + 6, name );
|
||||
if( stat( pdir_name, &buf ) )
|
||||
wcscpy( pdir_name + 6, name );
|
||||
if( wstat( pdir_name, &buf ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -536,17 +472,17 @@ static int find_process( const wchar_t *proc,
|
||||
{
|
||||
continue;
|
||||
}
|
||||
strcpy( pfile_name, pdir_name );
|
||||
strcat( pfile_name, "/cmdline" );
|
||||
wcscpy( pfile_name, pdir_name );
|
||||
wcscat( pfile_name, L"/cmdline" );
|
||||
|
||||
if( !stat( pfile_name, &buf ) )
|
||||
if( !wstat( pfile_name, &buf ) )
|
||||
{
|
||||
/*
|
||||
the 'cmdline' file exists, it should contain the commandline
|
||||
*/
|
||||
FILE *cmdfile;
|
||||
|
||||
if((cmdfile=fopen( pfile_name, "r" ))==0)
|
||||
if((cmdfile=wfopen( pfile_name, "r" ))==0)
|
||||
{
|
||||
wperror( L"fopen" );
|
||||
continue;
|
||||
@@ -561,15 +497,15 @@ static int find_process( const wchar_t *proc,
|
||||
else
|
||||
{
|
||||
#ifdef SunOS
|
||||
strcpy( pfile_name, pdir_name );
|
||||
strcat( pfile_name, "/psinfo" );
|
||||
if( !stat( pfile_name, &buf ) )
|
||||
wcscpy( pfile_name, pdir_name );
|
||||
wcscat( pfile_name, L"/psinfo" );
|
||||
if( !wstat( pfile_name, &buf ) )
|
||||
{
|
||||
psinfo_t info;
|
||||
|
||||
FILE *psfile;
|
||||
|
||||
if((psfile=fopen( pfile_name, "r" ))==0)
|
||||
if((psfile=wfopen( pfile_name, "r" ))==0)
|
||||
{
|
||||
wperror( L"fopen" );
|
||||
continue;
|
||||
@@ -608,7 +544,7 @@ static int find_process( const wchar_t *proc,
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t *res = str2wcs(name);
|
||||
wchar_t *res = wcsdup(name);
|
||||
if( res )
|
||||
al_push( out, res );
|
||||
}
|
||||
@@ -804,8 +740,7 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
-1,
|
||||
COMPLETE_VAR_NULL_DESC,
|
||||
in[stop_pos] );
|
||||
COMPLETE_VAR_NULL_DESC );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -873,7 +808,7 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
|
||||
|
||||
if( is_ok )
|
||||
{
|
||||
expand_variable_array( var_val, &var_item_list );
|
||||
tokenize_variable_array( var_val, &var_item_list );
|
||||
if( !all_vars )
|
||||
{
|
||||
int j;
|
||||
@@ -1403,7 +1338,6 @@ static void remove_internal_separator( const void *s, int conv )
|
||||
*out=0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The real expansion function. expand_one is just a wrapper around this one.
|
||||
*/
|
||||
@@ -1420,9 +1354,7 @@ int expand_string( void *context,
|
||||
int res = EXPAND_OK;
|
||||
int start_count = al_get_count( end_out );
|
||||
|
||||
// debug( 1, L"Expand %ls", str );
|
||||
|
||||
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) )
|
||||
if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( str ) )
|
||||
{
|
||||
halloc_register( context, str );
|
||||
al_push( end_out, str );
|
||||
@@ -1667,8 +1599,8 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags )
|
||||
array_list_t l;
|
||||
int res;
|
||||
wchar_t *one;
|
||||
|
||||
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( string ) )
|
||||
|
||||
if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( string ) )
|
||||
{
|
||||
halloc_register( context, string );
|
||||
return string;
|
||||
|
||||
36
expand.h
36
expand.h
@@ -112,6 +112,27 @@ enum
|
||||
/** String containing the character for separating two array elements */
|
||||
#define ARRAY_SEP_STR L"\x1e"
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_DESC _( L"The '$' character begins a variable name. The character '%lc', which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_NULL_DESC _( L"The '$' begins a variable name. It was given at the end of an argument. Variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_BRACKET_DESC _( L"Did you mean {$VARIABLE}? The '$' character begins a variable name. A bracket, which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'." )
|
||||
|
||||
/**
|
||||
Error issued on invalid variable name
|
||||
*/
|
||||
#define COMPLETE_VAR_PARAN_DESC _( L"Did you mean (COMMAND)? In fish, the '$' character is only used for accessing variables. To learn more about command substitution in fish, type 'help expand-command-substitution'.")
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -158,13 +179,14 @@ wchar_t *expand_tilde(wchar_t *in);
|
||||
|
||||
|
||||
/**
|
||||
Tokenize the specified string into the specified array_list_t.
|
||||
Each new element is allocated using malloc and must be freed by the
|
||||
caller.
|
||||
|
||||
\param val the input string. The contents of this string is not changed.
|
||||
\param out the list in which to place the elements.
|
||||
Test if the specified argument is clean, i.e. it does not contain
|
||||
any tokens which need to be expanded or otherwise altered. Clean
|
||||
strings can be passed through expand_string and expand_one without
|
||||
changing them. About two thirds of all strings are clean, so
|
||||
skipping expansion on them actually does save a small amount of
|
||||
time, since it avoids multiple memory allocations during the
|
||||
expansion process.
|
||||
*/
|
||||
void expand_variable_array( const wchar_t *val, array_list_t *out );
|
||||
int expand_is_clean( const wchar_t *in );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -990,9 +990,12 @@ int main( int argc, char **argv )
|
||||
|
||||
fwprintf( out_file, L"%ls", (wchar_t *)out_buff.buff );
|
||||
if( is_ca_mode )
|
||||
{
|
||||
writembs(exit_ca_mode);
|
||||
pager_flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
|
||||
9
fishd.c
9
fishd.c
@@ -110,6 +110,11 @@ time the original barrier request was sent have been received.
|
||||
*/
|
||||
#define LOCKTIMEOUT 1
|
||||
|
||||
/**
|
||||
Getopt short switches for fishd
|
||||
*/
|
||||
#define GETOPT_STRING "hv"
|
||||
|
||||
/**
|
||||
The list of connections to clients
|
||||
*/
|
||||
@@ -502,14 +507,14 @@ int main( int argc, char ** argv )
|
||||
|
||||
int opt = getopt_long( argc,
|
||||
argv,
|
||||
"hv",
|
||||
GETOPT_STRING,
|
||||
long_options,
|
||||
&opt_index );
|
||||
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
"hv" );
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
@@ -87,7 +87,7 @@ static void autoload_names( array_list_t *out, int get_hidden )
|
||||
|
||||
al_init( &path_list );
|
||||
|
||||
expand_variable_array( path_var, &path_list );
|
||||
tokenize_variable_array( path_var, &path_list );
|
||||
for( i=0; i<al_get_count( &path_list ); i++ )
|
||||
{
|
||||
wchar_t *ndir = (wchar_t *)al_get( &path_list, i );
|
||||
|
||||
308
highlight.c
308
highlight.c
@@ -40,11 +40,10 @@ static void highlight_universal_internal( wchar_t * buff,
|
||||
/**
|
||||
The environment variables used to specify the color of different tokens.
|
||||
*/
|
||||
static wchar_t *hightlight_var[] =
|
||||
static wchar_t *highlight_var[] =
|
||||
{
|
||||
L"fish_color_normal",
|
||||
L"fish_color_command",
|
||||
L"fish_color_subshell",
|
||||
L"fish_color_redirection",
|
||||
L"fish_color_end",
|
||||
L"fish_color_error",
|
||||
@@ -52,24 +51,24 @@ static wchar_t *hightlight_var[] =
|
||||
L"fish_color_comment",
|
||||
L"fish_color_match",
|
||||
L"fish_color_search_match",
|
||||
L"fish_color_pager_prefix",
|
||||
L"fish_color_pager_completion",
|
||||
L"fish_color_pager_description",
|
||||
L"fish_color_pager_progress"
|
||||
L"fish_color_operator",
|
||||
L"fish_color_escape",
|
||||
L"fish_color_quote"
|
||||
}
|
||||
;
|
||||
|
||||
#define VAR_COUNT ( sizeof(highlight_var)/sizeof(wchar_t *) )
|
||||
|
||||
int highlight_get_color( int highlight )
|
||||
{
|
||||
if( highlight < 0 )
|
||||
return FISH_COLOR_NORMAL;
|
||||
if( highlight >= (12) )
|
||||
if( highlight >= VAR_COUNT )
|
||||
return FISH_COLOR_NORMAL;
|
||||
|
||||
wchar_t *val = env_get( hightlight_var[highlight]);
|
||||
wchar_t *val = env_get( highlight_var[highlight]);
|
||||
if( val == 0 )
|
||||
val = env_get( hightlight_var[HIGHLIGHT_NORMAL]);
|
||||
val = env_get( highlight_var[HIGHLIGHT_NORMAL]);
|
||||
|
||||
if( val == 0 )
|
||||
{
|
||||
@@ -79,6 +78,289 @@ int highlight_get_color( int highlight )
|
||||
return output_color_code( val );
|
||||
}
|
||||
|
||||
/**
|
||||
Highligt operators (such as $, ~, %, as well as escaped characters.
|
||||
*/
|
||||
static void highlight_param( const wchar_t * buff,
|
||||
int *color,
|
||||
int pos,
|
||||
array_list_t *error )
|
||||
{
|
||||
|
||||
|
||||
int mode = 0;
|
||||
int in_pos, len = wcslen( buff );
|
||||
int bracket_count=0;
|
||||
wchar_t c;
|
||||
|
||||
for( in_pos=0;
|
||||
in_pos<len;
|
||||
in_pos++ )
|
||||
{
|
||||
c = buff[in_pos];
|
||||
switch( mode )
|
||||
{
|
||||
|
||||
/*
|
||||
Mode 0 means unquoted string
|
||||
*/
|
||||
case 0:
|
||||
{
|
||||
if( c == L'\\' )
|
||||
{
|
||||
int start_pos = in_pos;
|
||||
in_pos++;
|
||||
|
||||
if( wcschr( L"~%", buff[in_pos] ) )
|
||||
{
|
||||
if( in_pos == 1 )
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
}
|
||||
else if( buff[in_pos]==L',' )
|
||||
{
|
||||
if( bracket_count )
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
}
|
||||
else if( wcschr( L"nrtbe*?$(){}'\"<>^ \\#;|&", buff[in_pos] ) )
|
||||
{
|
||||
color[start_pos]=HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1]=HIGHLIGHT_NORMAL;
|
||||
}
|
||||
else if( wcschr( L"uUxX01234567", buff[in_pos] ) )
|
||||
{
|
||||
int i;
|
||||
long long res=0;
|
||||
int chars=2;
|
||||
int base=16;
|
||||
|
||||
int byte = 0;
|
||||
wchar_t max_val = ASCII_MAX;
|
||||
|
||||
switch( buff[in_pos] )
|
||||
{
|
||||
case L'u':
|
||||
{
|
||||
chars=4;
|
||||
max_val = UCS2_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'U':
|
||||
{
|
||||
chars=8;
|
||||
max_val = WCHAR_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'x':
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case L'X':
|
||||
{
|
||||
byte=1;
|
||||
max_val = BYTE_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
base=8;
|
||||
chars=3;
|
||||
in_pos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<chars; i++ )
|
||||
{
|
||||
int d = convert_digit( buff[++in_pos],base);
|
||||
|
||||
if( d < 0 )
|
||||
{
|
||||
in_pos--;
|
||||
break;
|
||||
}
|
||||
|
||||
res=(res*base)|d;
|
||||
}
|
||||
|
||||
if( (res <= max_val) )
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ERROR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( buff[in_pos]){
|
||||
case L'~':
|
||||
case L'%':
|
||||
{
|
||||
if( in_pos == 0 )
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case L'*':
|
||||
case L'?':
|
||||
case L'$':
|
||||
case L'(':
|
||||
case L')':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'{':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
bracket_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'}':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
bracket_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
case L',':
|
||||
{
|
||||
if( bracket_count )
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case L'\'':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_QUOTE;
|
||||
mode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case L'\"':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_QUOTE;
|
||||
mode = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
Mode 1 means single quoted string, i.e 'foo'
|
||||
*/
|
||||
case 1:
|
||||
{
|
||||
if( c == L'\\' )
|
||||
{
|
||||
int start_pos = in_pos;
|
||||
switch( buff[++in_pos] )
|
||||
{
|
||||
case '\\':
|
||||
case L'\'':
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1] = HIGHLIGHT_QUOTE;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0:
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if( c == L'\'' )
|
||||
{
|
||||
mode = 0;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
Mode 2 means double quoted string, i.e. "foo"
|
||||
*/
|
||||
case 2:
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case '"':
|
||||
{
|
||||
mode = 0;
|
||||
color[in_pos+1] = HIGHLIGHT_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
{
|
||||
int start_pos = in_pos;
|
||||
switch( buff[++in_pos] )
|
||||
{
|
||||
case L'\0':
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
case '\\':
|
||||
case L'$':
|
||||
case '"':
|
||||
{
|
||||
color[start_pos] = HIGHLIGHT_ESCAPE;
|
||||
color[in_pos+1] = HIGHLIGHT_QUOTE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case '$':
|
||||
{
|
||||
color[in_pos] = HIGHLIGHT_OPERATOR;
|
||||
color[in_pos+1] = HIGHLIGHT_QUOTE;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void highlight_shell( wchar_t * buff,
|
||||
int *color,
|
||||
@@ -125,6 +407,12 @@ void highlight_shell( wchar_t * buff,
|
||||
{
|
||||
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_PARAM;
|
||||
}
|
||||
|
||||
highlight_param( param,
|
||||
&color[tok_get_pos( &tok )],
|
||||
pos-tok_get_pos( &tok ),
|
||||
error );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -383,7 +671,7 @@ void highlight_shell( wchar_t * buff,
|
||||
*end=0;
|
||||
|
||||
highlight_shell( begin+1, color +(begin-buffcpy)+1, -1, error );
|
||||
color[end-buffcpy]=HIGHLIGHT_PARAM;
|
||||
color[end-buffcpy]=HIGHLIGHT_OPERATOR;
|
||||
|
||||
if( done )
|
||||
break;
|
||||
|
||||
9
mimedb.c
9
mimedb.c
@@ -88,6 +88,11 @@ license. Read the source code of the library for more information.
|
||||
*/
|
||||
#define MIMEDB "mimedb"
|
||||
|
||||
/**
|
||||
Getopt short switches for mimedb
|
||||
*/
|
||||
#define GETOPT_STRING "tfimdalhv"
|
||||
|
||||
/**
|
||||
All types of input and output possible
|
||||
*/
|
||||
@@ -1216,14 +1221,14 @@ int main (int argc, char *argv[])
|
||||
|
||||
int opt = getopt_long( argc,
|
||||
argv,
|
||||
"tfimdalhv",
|
||||
GETOPT_STRING,
|
||||
long_options,
|
||||
&opt_index );
|
||||
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
"tfimdalhv" );
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
91
output.c
91
output.c
@@ -128,9 +128,20 @@ void set_color( int c, int c2 )
|
||||
{
|
||||
static int last_color = FISH_COLOR_NORMAL;
|
||||
static int last_color2 = FISH_COLOR_NORMAL;
|
||||
static int was_bold=0;
|
||||
int bg_set=0, last_bg_set=0;
|
||||
char *fg = 0, *bg=0;
|
||||
|
||||
int is_bold = 0;
|
||||
|
||||
is_bold |= (c&FISH_COLOR_BOLD)!=0;
|
||||
is_bold |= (c2&FISH_COLOR_BOLD)!=0;
|
||||
|
||||
// debug( 1, L"WOO %d %d %d", is_bold, c&FISH_COLOR_BOLD,c2&FISH_COLOR_BOLD);
|
||||
|
||||
c = c&(~FISH_COLOR_BOLD);
|
||||
c2 = c2&(~FISH_COLOR_BOLD);
|
||||
|
||||
if( (set_a_foreground != 0) && (strlen( set_a_foreground) != 0 ) )
|
||||
{
|
||||
fg = set_a_foreground;
|
||||
@@ -145,14 +156,31 @@ void set_color( int c, int c2 )
|
||||
if( (c == FISH_COLOR_RESET) || (c2 == FISH_COLOR_RESET))
|
||||
{
|
||||
c = c2 = FISH_COLOR_NORMAL;
|
||||
was_bold=0;
|
||||
if( fg )
|
||||
{
|
||||
/*
|
||||
If we exit attibute mode, we must first set a color, or
|
||||
previously coloured text might lose it's
|
||||
color. Terminals are weird...
|
||||
*/
|
||||
writembs( tparm( fg, 0 ) );
|
||||
}
|
||||
writembs( exit_attribute_mode );
|
||||
return;
|
||||
}
|
||||
|
||||
if( was_bold && !is_bold )
|
||||
{
|
||||
/*
|
||||
Only way to exit bold mode is a reset of all attributes.
|
||||
*/
|
||||
writembs( exit_attribute_mode );
|
||||
last_color = FISH_COLOR_NORMAL;
|
||||
last_color2 = FISH_COLOR_NORMAL;
|
||||
was_bold=0;
|
||||
}
|
||||
|
||||
if( last_color2 != FISH_COLOR_NORMAL &&
|
||||
last_color2 != FISH_COLOR_RESET &&
|
||||
last_color2 != FISH_COLOR_IGNORE )
|
||||
@@ -164,7 +192,6 @@ void set_color( int c, int c2 )
|
||||
}
|
||||
|
||||
if( c2 != FISH_COLOR_NORMAL &&
|
||||
c2 != FISH_COLOR_RESET &&
|
||||
c2 != FISH_COLOR_IGNORE )
|
||||
{
|
||||
/*
|
||||
@@ -180,7 +207,8 @@ void set_color( int c, int c2 )
|
||||
{
|
||||
/*
|
||||
Background color changed and is set, so we enter bold
|
||||
mode to make reading easier
|
||||
mode to make reading easier. This means bold mode is
|
||||
_always_ on when the background color is set.
|
||||
*/
|
||||
writembs( enter_bold_mode );
|
||||
}
|
||||
@@ -252,8 +280,21 @@ void set_color( int c, int c2 )
|
||||
last_color2 = c2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Lastly, we set bold mode correctly
|
||||
*/
|
||||
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set )
|
||||
{
|
||||
if( is_bold && !was_bold )
|
||||
{
|
||||
writembs( tparm( enter_bold_mode ) );
|
||||
}
|
||||
was_bold = is_bold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
perm_left_cursor and parm_right_cursor don't seem to be properly
|
||||
emulated by many terminal emulators, so we only use plain
|
||||
@@ -475,23 +516,37 @@ int writespace( int c )
|
||||
|
||||
int output_color_code( const wchar_t *val )
|
||||
{
|
||||
int i, color=-1;
|
||||
int j, i, color=FISH_COLOR_NORMAL;
|
||||
array_list_t el;
|
||||
int is_bold=0;
|
||||
|
||||
for( i=0; i<COLORS; i++ )
|
||||
{
|
||||
if( wcscasecmp( col[i], val ) == 0 )
|
||||
{
|
||||
color = col_idx[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( color >= 0 )
|
||||
{
|
||||
return color;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !val )
|
||||
return FISH_COLOR_NORMAL;
|
||||
|
||||
al_init( &el );
|
||||
tokenize_variable_array( val, &el );
|
||||
|
||||
for( j=0; j<al_get_count( &el ); j++ )
|
||||
{
|
||||
wchar_t *next = (wchar_t *)al_get( &el, j );
|
||||
|
||||
is_bold |= (wcsncmp( next, L"--bold", wcslen(next) ) == 0 ) && wcslen(next)>=3;
|
||||
is_bold |= wcscmp( next, L"-b" ) == 0;
|
||||
|
||||
for( i=0; i<COLORS; i++ )
|
||||
{
|
||||
if( wcscasecmp( col[i], next ) == 0 )
|
||||
{
|
||||
color = col_idx[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
al_foreach( &el, (void (*)(const void *))&free );
|
||||
al_destroy( &el );
|
||||
|
||||
return color | (is_bold?FISH_COLOR_BOLD:0);
|
||||
|
||||
}
|
||||
|
||||
11
output.h
11
output.h
@@ -14,7 +14,6 @@ enum
|
||||
{
|
||||
HIGHLIGHT_NORMAL,
|
||||
HIGHLIGHT_COMMAND,
|
||||
HIGHLIGHT_SUBSHELL,
|
||||
HIGHLIGHT_REDIRECTION,
|
||||
HIGHLIGHT_END,
|
||||
HIGHLIGHT_ERROR,
|
||||
@@ -22,6 +21,9 @@ enum
|
||||
HIGHLIGHT_COMMENT,
|
||||
HIGHLIGHT_MATCH,
|
||||
HIGHLIGHT_SEARCH_MATCH,
|
||||
HIGHLIGHT_OPERATOR,
|
||||
HIGHLIGHT_ESCAPE,
|
||||
HIGHLIGHT_QUOTE,
|
||||
}
|
||||
;
|
||||
|
||||
@@ -39,10 +41,13 @@ enum
|
||||
FISH_COLOR_CYAN,
|
||||
FISH_COLOR_WHITE,
|
||||
/** The default fg color of the terminal */
|
||||
FISH_COLOR_NORMAL
|
||||
FISH_COLOR_NORMAL,
|
||||
FISH_COLOR_IGNORE,
|
||||
FISH_COLOR_RESET
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
#define FISH_COLOR_BOLD 0x80
|
||||
|
||||
/**
|
||||
Sets the fg and bg color. May be called as often as you like, since
|
||||
|
||||
@@ -558,7 +558,7 @@ int parse_util_load( const wchar_t *cmd,
|
||||
else
|
||||
sb_clear( path );
|
||||
|
||||
expand_variable_array( path_var, path_list );
|
||||
tokenize_variable_array( path_var, path_list );
|
||||
|
||||
/*
|
||||
Iterate over path searching for suitable completion files
|
||||
|
||||
485
parser.c
485
parser.c
@@ -76,7 +76,7 @@ The fish parser. Contains functions for parsing code.
|
||||
/**
|
||||
Error message for short circuit command error.
|
||||
*/
|
||||
#define COND_ERR_MSG _( L"Short circuit command requires additional command")
|
||||
#define COND_ERR_MSG _( L"Pipe or short circuit command requires additional command")
|
||||
|
||||
/**
|
||||
Error message on reaching maximum recusrion depth
|
||||
@@ -252,6 +252,10 @@ The fish parser. Contains functions for parsing code.
|
||||
#define UNKNOWN_BLOCK _( L"unknown/invalid block" )
|
||||
|
||||
|
||||
/**
|
||||
Size of the error string buffer
|
||||
*/
|
||||
#define ERR_STR_SZ 1024
|
||||
/** Last error code */
|
||||
int error_code;
|
||||
|
||||
@@ -262,7 +266,7 @@ event_block_t *global_event_block=0;
|
||||
static int err_pos;
|
||||
|
||||
/** Description of last error */
|
||||
static wchar_t err_str[256];
|
||||
static wchar_t err_str[ERR_STR_SZ];
|
||||
|
||||
/** Pointer to the current tokenizer */
|
||||
static tokenizer *current_tokenizer;
|
||||
@@ -698,7 +702,7 @@ void error( int ec, int p, const wchar_t *str, ... )
|
||||
err_pos = p;
|
||||
|
||||
va_start( va, str );
|
||||
vswprintf( err_str, 256, str, va );
|
||||
vswprintf( err_str, ERR_STR_SZ, str, va );
|
||||
va_end( va );
|
||||
|
||||
}
|
||||
@@ -1976,7 +1980,7 @@ static int parse_job( process_t *p,
|
||||
|
||||
tmp = (wchar_t *)al_get( args, 0 );
|
||||
al_truncate( args, 0 );
|
||||
al_push( args, wcsdup( L"cd" ) );
|
||||
al_push( args, halloc_wcsdup( j, L"cd" ) );
|
||||
al_push( args, tmp );
|
||||
/*
|
||||
If we have defined a wrapper around cd, use it,
|
||||
@@ -1994,7 +1998,7 @@ static int parse_job( process_t *p,
|
||||
|
||||
/*
|
||||
We couln't find the specified command.
|
||||
|
||||
|
||||
What we want to happen now is that the
|
||||
specified job won't get executed, and an
|
||||
error message is printed on-screen, but
|
||||
@@ -2542,11 +2546,258 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
||||
return code;
|
||||
}
|
||||
|
||||
int parser_test( wchar_t * buff,
|
||||
static int parser_get_block_type( const wchar_t *cmd )
|
||||
{
|
||||
if( wcscmp( cmd, L"while") == 0 )
|
||||
return WHILE;
|
||||
else if( wcscmp( cmd, L"for") == 0 )
|
||||
return FOR;
|
||||
else if( wcscmp( cmd, L"switch") == 0 )
|
||||
return SWITCH;
|
||||
else if( wcscmp( cmd, L"if") == 0 )
|
||||
return IF;
|
||||
else if( wcscmp( cmd, L"function") == 0 )
|
||||
return FUNCTION_DEF;
|
||||
else if( wcscmp( cmd, L"begin") == 0 )
|
||||
return BEGIN;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int parser_test_argument( const wchar_t *arg, int babble, int offset )
|
||||
{
|
||||
wchar_t *unesc;
|
||||
wchar_t *pos;
|
||||
int err=0;
|
||||
|
||||
const wchar_t *paran_begin, *paran_end;
|
||||
wchar_t *arg_cpy = wcsdup( arg );
|
||||
int do_loop = 1;
|
||||
|
||||
while( do_loop )
|
||||
{
|
||||
switch( parse_util_locate_cmdsubst(arg_cpy,
|
||||
¶n_begin,
|
||||
¶n_end,
|
||||
0 ) )
|
||||
{
|
||||
case -1:
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
offset,
|
||||
L"Mismatched parans" );
|
||||
print_errors();
|
||||
}
|
||||
free( arg_cpy );
|
||||
return 1;
|
||||
|
||||
case 0:
|
||||
do_loop = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
|
||||
wchar_t *subst = wcsndup( paran_begin+1, paran_end-paran_begin-1 );
|
||||
string_buffer_t tmp;
|
||||
sb_init( &tmp );
|
||||
|
||||
sb_append_substring( &tmp, arg_cpy, paran_begin - arg_cpy);
|
||||
sb_append_char( &tmp, INTERNAL_SEPARATOR);
|
||||
sb_append( &tmp, paran_end+1);
|
||||
|
||||
// debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff );
|
||||
|
||||
err |= parser_test( subst, babble );
|
||||
|
||||
free( subst );
|
||||
free( arg_cpy );
|
||||
arg_cpy = (wchar_t *)tmp.buff;
|
||||
|
||||
/*
|
||||
Do _not_ call sb_destroy on this stringbuffer - it's
|
||||
buffer is used as the new 'arg_cpy'. It is free'd at
|
||||
the end of the loop.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unesc = unescape( arg_cpy, 1 );
|
||||
free( arg_cpy );
|
||||
|
||||
/*
|
||||
Check for invalid variable expansions
|
||||
*/
|
||||
for( pos = unesc; *pos; pos++ )
|
||||
{
|
||||
switch( *pos )
|
||||
{
|
||||
case VARIABLE_EXPAND:
|
||||
case VARIABLE_EXPAND_SINGLE:
|
||||
{
|
||||
switch( *(pos+1))
|
||||
{
|
||||
case BRACKET_BEGIN:
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
offset,
|
||||
COMPLETE_VAR_BRACKET_DESC );
|
||||
|
||||
print_errors();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case INTERNAL_SEPARATOR:
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
offset,
|
||||
COMPLETE_VAR_PARAN_DESC );
|
||||
print_errors();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0:
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
offset,
|
||||
COMPLETE_VAR_NULL_DESC );
|
||||
print_errors();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if( !iswalnum(*(pos+1)) &&
|
||||
*(pos+1)!=L'_' &&
|
||||
*(pos+1)!=VARIABLE_EXPAND &&
|
||||
*(pos+1)!=VARIABLE_EXPAND_SINGLE )
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
offset,
|
||||
COMPLETE_VAR_DESC,
|
||||
*(pos+1) );
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
free( unesc );
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int parser_test_args(const wchar_t * buff,
|
||||
int babble )
|
||||
{
|
||||
tokenizer tok;
|
||||
tokenizer *previous_tokenizer = current_tokenizer;
|
||||
int previous_pos = current_tokenizer_pos;
|
||||
int do_loop = 1;
|
||||
int err = 0;
|
||||
|
||||
current_tokenizer = &tok;
|
||||
|
||||
for( tok_init( &tok, buff, 0 );
|
||||
do_loop && tok_has_next( &tok );
|
||||
tok_next( &tok ) )
|
||||
{
|
||||
current_tokenizer_pos = tok_get_pos( &tok );
|
||||
switch( tok_last_type( &tok ) )
|
||||
{
|
||||
|
||||
case TOK_STRING:
|
||||
{
|
||||
err |= parser_test_argument( tok_last( &tok ), babble, tok_get_pos( &tok ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_END:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_ERROR:
|
||||
{
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
TOK_ERR_MSG,
|
||||
tok_last(&tok) );
|
||||
print_errors();
|
||||
}
|
||||
err=1;
|
||||
do_loop=0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
UNEXPECTED_TOKEN_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok)) );
|
||||
print_errors();
|
||||
}
|
||||
err=1;
|
||||
do_loop=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tok_destroy( &tok );
|
||||
|
||||
current_tokenizer=previous_tokenizer;
|
||||
current_tokenizer_pos = previous_pos;
|
||||
|
||||
error_code=0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int parser_test( const wchar_t * buff,
|
||||
int babble )
|
||||
{
|
||||
tokenizer tok;
|
||||
int had_cmd=0;
|
||||
/*
|
||||
Set to one if a command name has been given for the currently
|
||||
parsed process specification
|
||||
*/
|
||||
int had_cmd=0;
|
||||
int count = 0;
|
||||
int err=0;
|
||||
tokenizer *previous_tokenizer=current_tokenizer;
|
||||
@@ -2554,10 +2805,18 @@ int parser_test( wchar_t * buff,
|
||||
static int block_pos[BLOCK_MAX_COUNT];
|
||||
static int block_type[BLOCK_MAX_COUNT];
|
||||
int is_pipeline = 0;
|
||||
/*
|
||||
Set to one if the currently specified process can not be used inside a pipeline
|
||||
*/
|
||||
int forbid_pipeline = 0;
|
||||
int needs_cmd=0;
|
||||
int require_additional_commands=0;
|
||||
|
||||
/*
|
||||
Set to one if an additional process specification is needed
|
||||
*/
|
||||
int needs_cmd=0;
|
||||
void *context = halloc( 0, 0 );
|
||||
int arg_count=0;
|
||||
wchar_t *cmd=0;
|
||||
|
||||
current_tokenizer = &tok;
|
||||
|
||||
for( tok_init( &tok, buff, 0 );
|
||||
@@ -2575,10 +2834,32 @@ int parser_test( wchar_t * buff,
|
||||
{
|
||||
int mark = tok_get_pos( &tok );
|
||||
had_cmd = 1;
|
||||
|
||||
if( require_additional_commands )
|
||||
arg_count=0;
|
||||
|
||||
if( !(cmd = expand_one( context,
|
||||
wcsdup( tok_last( &tok ) ),
|
||||
EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES ) ) )
|
||||
{
|
||||
if( contains_str( tok_last(&tok),
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
ILLEGAL_CMD_ERR_MSG,
|
||||
cmd );
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
|
||||
if( needs_cmd )
|
||||
{
|
||||
/*
|
||||
end is not a valid command when a followup
|
||||
command is needed, such as after 'and' or
|
||||
'while'
|
||||
*/
|
||||
if( contains_str( cmd,
|
||||
L"end",
|
||||
0 ) )
|
||||
{
|
||||
@@ -2588,18 +2869,18 @@ int parser_test( wchar_t * buff,
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
COND_ERR_MSG );
|
||||
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
|
||||
require_additional_commands--;
|
||||
|
||||
needs_cmd=0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Decrement block count on end command
|
||||
*/
|
||||
if( wcscmp(tok_last(&tok), L"end")==0)
|
||||
if( wcscmp(cmd, L"end")==0)
|
||||
{
|
||||
tok_next( &tok );
|
||||
count--;
|
||||
@@ -2609,7 +2890,7 @@ int parser_test( wchar_t * buff,
|
||||
/*
|
||||
Handle block commands
|
||||
*/
|
||||
if( parser_is_block( tok_last(&tok) ) )
|
||||
if( parser_is_block( cmd ) )
|
||||
{
|
||||
if( count >= BLOCK_MAX_COUNT )
|
||||
{
|
||||
@@ -2621,24 +2902,7 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
else
|
||||
{
|
||||
if( wcscmp( tok_last(&tok), L"while") == 0 )
|
||||
block_type[count] = WHILE;
|
||||
else if( wcscmp( tok_last(&tok), L"for") == 0 )
|
||||
block_type[count] = FOR;
|
||||
else if( wcscmp( tok_last(&tok), L"switch") == 0 )
|
||||
block_type[count] = SWITCH;
|
||||
else if( wcscmp( tok_last(&tok), L"if") == 0 )
|
||||
block_type[count] = IF;
|
||||
else if( wcscmp( tok_last(&tok), L"function") == 0 )
|
||||
block_type[count] = FUNCTION_DEF;
|
||||
else if( wcscmp( tok_last(&tok), L"begin") == 0 )
|
||||
block_type[count] = BEGIN;
|
||||
else
|
||||
block_type[count] = -1;
|
||||
|
||||
// debug( 2, L"add block of type %d after cmd %ls\n", block_type[count], tok_last(&tok) );
|
||||
|
||||
|
||||
block_type[count] = parser_get_block_type( cmd );
|
||||
block_pos[count] = current_tokenizer_pos;
|
||||
tok_next( &tok );
|
||||
count++;
|
||||
@@ -2652,20 +2916,20 @@ int parser_test( wchar_t * buff,
|
||||
argument. If parser_skip_arguments is true, the
|
||||
second argument is optional.
|
||||
*/
|
||||
if( parser_is_subcommand( tok_last( &tok ) ) && !parser_skip_arguments(tok_last( &tok ) ) )
|
||||
if( parser_is_subcommand( cmd ) && !parser_skip_arguments(cmd ) )
|
||||
{
|
||||
needs_cmd = 1;
|
||||
had_cmd = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
The short circuit commands requires _two_ additional commands.
|
||||
*/
|
||||
if( contains_str( tok_last( &tok ),
|
||||
|
||||
if( contains_str( cmd,
|
||||
L"or",
|
||||
L"and",
|
||||
0 ) )
|
||||
{
|
||||
/*
|
||||
'or' and 'and' can not be used inside pipelines
|
||||
*/
|
||||
if( is_pipeline )
|
||||
{
|
||||
err=1;
|
||||
@@ -2679,15 +2943,14 @@ int parser_test( wchar_t * buff,
|
||||
|
||||
}
|
||||
}
|
||||
require_additional_commands=1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
There are a lot of situations where pipelines
|
||||
are forbidden, inclusing when using the exec
|
||||
are forbidden, including when using the exec
|
||||
builtin.
|
||||
*/
|
||||
if( parser_is_pipe_forbidden( tok_last( &tok ) ) )
|
||||
if( parser_is_pipe_forbidden( cmd ) )
|
||||
{
|
||||
if( is_pipeline )
|
||||
{
|
||||
@@ -2706,17 +2969,14 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
|
||||
/*
|
||||
Test that the case builtin is only used in a switch block
|
||||
Test that the case builtin is only used directly in a switch block
|
||||
*/
|
||||
if( wcscmp( L"case", tok_last( &tok ) )==0 )
|
||||
if( wcscmp( L"case", cmd )==0 )
|
||||
{
|
||||
if( !count || block_type[count-1]!=SWITCH )
|
||||
{
|
||||
err=1;
|
||||
|
||||
// debug( 2, L"Error on block type %d\n", block_type[count-1] );
|
||||
|
||||
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
@@ -2729,10 +2989,9 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
|
||||
/*
|
||||
Test that break and continue are only used in loop blocks
|
||||
Test that break and continue are only used within loop blocks
|
||||
*/
|
||||
if( wcscmp( L"break", tok_last( &tok ) )==0 ||
|
||||
wcscmp( L"continue", tok_last( &tok ) )==0)
|
||||
if( contains_str( cmd, L"break", L"continue", (void *)0 ) )
|
||||
{
|
||||
int found_loop=0;
|
||||
int i;
|
||||
@@ -2761,9 +3020,9 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
|
||||
/*
|
||||
Test that else is only used in an if-block
|
||||
Test that else is only used directly in an if-block
|
||||
*/
|
||||
if( wcscmp( L"else", tok_last( &tok ) )==0 )
|
||||
if( wcscmp( L"else", cmd )==0 )
|
||||
{
|
||||
if( !count || block_type[count-1]!=IF )
|
||||
{
|
||||
@@ -2781,7 +3040,7 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
|
||||
/*
|
||||
Test that end is not used when not inside a blovk
|
||||
Test that end is not used when not inside any block
|
||||
*/
|
||||
if( count < 0 )
|
||||
{
|
||||
@@ -2795,6 +3054,47 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err |= parser_test_argument( tok_last( &tok ), babble, tok_get_pos( &tok ) );
|
||||
|
||||
/*
|
||||
If possible, keep track of number of supplied arguments
|
||||
*/
|
||||
if( arg_count >= 0 && expand_is_clean( tok_last( &tok ) ) )
|
||||
{
|
||||
arg_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_count = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Try to make sure the second argument to 'for' is 'in'
|
||||
*/
|
||||
if( wcscmp( cmd, L"for" ) == 0 )
|
||||
{
|
||||
if( arg_count == 2 )
|
||||
{
|
||||
if( wcscmp( tok_last( &tok ), L"in" ) != 0 )
|
||||
{
|
||||
err = 1;
|
||||
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
BUILTIN_FOR_ERR_IN,
|
||||
L"for" );
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2840,7 +3140,31 @@ int parser_test( wchar_t * buff,
|
||||
|
||||
case TOK_PIPE:
|
||||
{
|
||||
if( forbid_pipeline )
|
||||
if( !had_cmd )
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
{
|
||||
if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'|' )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
CMD_OR_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok) ) );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
CMD_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok)));
|
||||
}
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
else if( forbid_pipeline )
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
@@ -2848,31 +3172,46 @@ int parser_test( wchar_t * buff,
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
EXEC_ERR_MSG );
|
||||
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
needs_cmd=0;
|
||||
is_pipeline=1;
|
||||
else
|
||||
{
|
||||
needs_cmd=1;
|
||||
is_pipeline=1;
|
||||
had_cmd=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
case TOK_BACKGROUND:
|
||||
{
|
||||
if( needs_cmd && !had_cmd )
|
||||
if( !had_cmd )
|
||||
{
|
||||
err = 1;
|
||||
if( babble )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
CMD_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok)));
|
||||
|
||||
if( tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'&' )
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
CMD_AND_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok) ) );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
error( SYNTAX_ERROR,
|
||||
tok_get_pos( &tok ),
|
||||
CMD_ERR_MSG,
|
||||
tok_get_desc( tok_last_type(&tok)));
|
||||
}
|
||||
|
||||
print_errors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( had_cmd )
|
||||
{
|
||||
had_cmd = 0;
|
||||
@@ -2898,7 +3237,7 @@ int parser_test( wchar_t * buff,
|
||||
}
|
||||
}
|
||||
|
||||
if( require_additional_commands )
|
||||
if( needs_cmd )
|
||||
{
|
||||
err=1;
|
||||
if( babble )
|
||||
@@ -2928,6 +3267,8 @@ int parser_test( wchar_t * buff,
|
||||
|
||||
error_code=0;
|
||||
|
||||
halloc_free( context );
|
||||
|
||||
return err | ((count!=0)<<1);
|
||||
}
|
||||
|
||||
|
||||
16
parser.h
16
parser.h
@@ -315,10 +315,20 @@ const wchar_t *parser_get_block_desc( int block );
|
||||
|
||||
|
||||
/**
|
||||
Test if the specified string can be parsed, or if more bytes need to be read first.
|
||||
The result has the first bit set if the string contains errors, and the second bit is set if the string contains an unclosed block.
|
||||
Test if the specified string can be parsed, or if more bytes need
|
||||
to be read first. The result has the first bit set if the string
|
||||
contains errors, and the second bit is set if the string contains
|
||||
an unclosed block.
|
||||
*/
|
||||
int parser_test( wchar_t * buff, int babble );
|
||||
int parser_test( const wchar_t * buff, int babble );
|
||||
|
||||
/**
|
||||
Test if the specified string can be parsed as an argument list,
|
||||
e.g. sent to eval_args. The result has the first bit set if the
|
||||
string contains errors, and the second bit is set if the string
|
||||
contains an unclosed block.
|
||||
*/
|
||||
int parser_test_args( const wchar_t * buff, int babble );
|
||||
|
||||
/**
|
||||
Returns the full path of the specified directory. If the \c in is a
|
||||
|
||||
15
reader.c
15
reader.c
@@ -917,7 +917,7 @@ void repaint()
|
||||
if( steps )
|
||||
move_cursor( -steps );
|
||||
|
||||
set_color( FISH_COLOR_NORMAL, -1 );
|
||||
set_color( FISH_COLOR_NORMAL, FISH_COLOR_IGNORE );
|
||||
reader_save_status();
|
||||
}
|
||||
|
||||
@@ -1144,7 +1144,7 @@ static int insert_char( int c )
|
||||
}
|
||||
else
|
||||
writech(c);
|
||||
set_color( FISH_COLOR_NORMAL, -1 );
|
||||
set_color( FISH_COLOR_NORMAL, FISH_COLOR_IGNORE );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2082,7 +2082,7 @@ void reader_run_command( wchar_t *cmd )
|
||||
|
||||
term_steal();
|
||||
|
||||
env_set( L"_", L"fish", ENV_GLOBAL );
|
||||
env_set( L"_", program_name, ENV_GLOBAL );
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
proc_update_jiffies();
|
||||
@@ -2099,7 +2099,13 @@ void reader_run_command( wchar_t *cmd )
|
||||
|
||||
static int shell_test( wchar_t *b )
|
||||
{
|
||||
return !wcslen(b);
|
||||
if( parser_test( b, 0 ) )
|
||||
{
|
||||
writech( L'\n' );
|
||||
parser_test( b, 1 );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2467,7 +2473,6 @@ wchar_t *reader_readline()
|
||||
{
|
||||
exit_forced = 1;
|
||||
data->end_loop=1;
|
||||
debug( 1, L"got R_EOF" );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
4
seq.in
4
seq.in
@@ -34,14 +34,14 @@ switch (count $argv)
|
||||
|
||||
case '*'
|
||||
printf (_ "%s: Expected 1, 2 or 3 arguments, got %d\n") seq (count $argv)
|
||||
return 1
|
||||
exit 1
|
||||
|
||||
end
|
||||
|
||||
for i in $from $step $to
|
||||
if not echo $i | grep '^-\?[0-9]*\(\|.[0-9]\+\)$' >/dev/null
|
||||
printf (_ "%s: '%s' is not a number\n") seq $i
|
||||
return 1
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
*/
|
||||
#define SET_COLOR "set_color"
|
||||
|
||||
/**
|
||||
Getopt short switches for set_color
|
||||
*/
|
||||
#define GETOPT_STRING "b:hvoc"
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
#define _(string) gettext(string)
|
||||
#else
|
||||
@@ -186,13 +191,13 @@ int main( int argc, char **argv )
|
||||
|
||||
int opt = getopt_long( argc,
|
||||
argv,
|
||||
"b:hvoc",
|
||||
GETOPT_STRING,
|
||||
long_options,
|
||||
&opt_index );
|
||||
#else
|
||||
int opt = getopt( argc,
|
||||
argv,
|
||||
"b:hvoc" );
|
||||
GETOPT_STRING );
|
||||
#endif
|
||||
if( opt == -1 )
|
||||
break;
|
||||
|
||||
@@ -4,7 +4,7 @@ complete -f -c apt-proxy-import -s V -l version -d (N_ 'Display version and exit
|
||||
complete -f -c apt-proxy-import -s v -l verbose -d (N_ 'Verbose mode')
|
||||
complete -f -c apt-proxy-import -s q -l quiet -d (N_ 'No message to STDOUT')
|
||||
complete -f -c apt-proxy-import -s r -l recursive -d (N_ 'Recurse into subdir')
|
||||
complete -r -c apt-proxy-import -s i -l import-dir -a '(ls -Fp|grep /$)' -d (N_ 'Dir to import')
|
||||
complete -r -c apt-proxy-import -s i -l import-dir -a '(ls -Fp|grep /\$)' -d (N_ 'Dir to import')
|
||||
complete -r -c apt-proxy-import -s u -l user -a '(__fish_complete_users)' -d (N_ 'Change to user')
|
||||
complete -r -c apt-proxy-import -s d -l debug -d (N_ 'Debug level[default 0]')
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
complete -c apt-show-source -s h -l help -d (N_ 'Display help and exit')
|
||||
complete -r -c apt-show-source -l status-file -d (N_ 'Read package from file') -f
|
||||
complete -r -c apt-show-source -o stf -d (N_ 'Read package from file') -f
|
||||
complete -r -c apt-show-source -l list-dir -a '(ls -Fp .|grep /$) /var/lib/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-source -o ld -a '(ls -Fp .|grep /$) /var/lib/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-source -l list-dir -a '(ls -Fp .|grep /\$) /var/lib/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-source -o ld -a '(ls -Fp .|grep /\$) /var/lib/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-source -s p -l package -a '(apt-cache pkgnames)' -d (N_ 'List PKG info')
|
||||
complete -f -c apt-show-source -l version-only -d (N_ 'Display version and exit')
|
||||
complete -f -c apt-show-source -s a -l all -d (N_ 'Print all source packages with version')
|
||||
|
||||
@@ -9,6 +9,6 @@ complete -f -c apt-show-versions -s v -l verbose -d (N_ 'Print verbose info')
|
||||
complete -f -c apt-show-versions -s i -l initialize -d (N_ 'Init or update cache only')
|
||||
complete -r -c apt-show-versions -l status-file -d (N_ 'Read package from file')
|
||||
complete -r -c apt-show-versions -o stf -d (N_ 'Read package from file')
|
||||
complete -r -c apt-show-versions -l list-dir -a '(ls -Fp .|grep /$) /var/lib/apt/lists /var/state/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-versions -o ld -a '(ls -Fp .|grep /$) /var/lib/apt/lists /var/state/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-versions -l list-dir -a '(ls -Fp .|grep /\$) /var/lib/apt/lists /var/state/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
complete -r -c apt-show-versions -o ld -a '(ls -Fp .|grep /\$) /var/lib/apt/lists /var/state/apt/lists' -d (N_ 'Specify APT list dir')
|
||||
|
||||
|
||||
@@ -12,3 +12,4 @@ complete -c complete -s u -l unauthorative -d (N_ "Option list is not complete")
|
||||
complete -c complete -s e -l erase -d (N_ "Remove completion")
|
||||
complete -c complete -s h -l help -d (N_ "Display help and exit")
|
||||
complete -c complete -s C -l do-complete -d (N_ "Print all completions for the specified commandline")
|
||||
complete -c complete -s n -l complete -d (N_ "The completion should only be used if the specified command has a zero exit status") -r
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
complete -c fusermount -d (N_ "Mount point") -x -a '
|
||||
(
|
||||
cat /etc/mtab | grep "^sshfs" | cut -d " " -f 1-2|tr " " \n|sed -e "s/[0-9\.]*:\//\//"|grep "^/"
|
||||
cat /etc/mtab | grep "^fuseiso" | cut -d " " -f 1-2|tr " " \n|sed -e "s/[0-9\.]*:\//\//"|grep "^/"
|
||||
)
|
||||
'
|
||||
|
||||
@@ -15,3 +16,4 @@ complete -c fusermount -s o -x -d (N_ "Mount options")
|
||||
complete -c fusermount -s u -d (N_ "Unmount")
|
||||
complete -c fusermount -s q -d (N_ "Quiet")
|
||||
complete -c fusermount -s z -d (N_ "Lazy unmount")
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ for i in (builtin -n)
|
||||
complete -c help -x -a $i -d (N_ "Help for the specified builtin")
|
||||
end
|
||||
|
||||
for i in count dirh dirs help mimedb nextd open popd prevd pushd set_color psub umask type
|
||||
for i in case (sed -n < /usr/share/doc/fish-1.21.7/commands.html -e "s/.*<h2><a class=\"anchor\" name=\"\([^\"]*\)\">.*/\1/p")
|
||||
complete -c help -x -a $i -d (N_ "Help for the specified command")
|
||||
end
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ complete -x -c ssh -s b -d (N_ "Interface to transmit from") -a "
|
||||
)
|
||||
"
|
||||
|
||||
complete -x -c ssh -s e -d (N_ "Escape character") -a "^ none"
|
||||
complete -x -c ssh -s e -d (N_ "Escape character") -a "\^ none"
|
||||
complete -c ssh -s f -d (N_ "Go to background")
|
||||
complete -c ssh -s g -d (N_ "Allow remote host to connect to local forwarded ports")
|
||||
complete -c ssh -s I -d (N_ "Smartcard device")
|
||||
|
||||
@@ -43,7 +43,7 @@ complete -xc valgrind -l input-fd -d (N_ "File descriptor for input") -a "0 1 2
|
||||
|
||||
|
||||
# Memcheck-specific options
|
||||
complete -n "__fish_valgrind_skin memcheck" -xc valgrind -l leak-check -d (N_ "Check for memory leaks") -a "no\tDon't\ check\ for\ memory\ leaks summary\t'Show a leak summary' full\t'Describe memory leaks in detail'"
|
||||
complete -n "__fish_valgrind_skin memcheck" -xc valgrind -l leak-check -d (N_ "Check for memory leaks") -a "no\tDon\'t\ check\ for\ memory\ leaks summary\t'Show a leak summary' full\t'Describe memory leaks in detail'"
|
||||
complete -n "__fish_valgrind_skin memcheck" -xc valgrind -l show-reachable -d (N_ "Show reachable leaked memory") -a "yes\t'Show reachable leaked memory' no\t'Do not show reachable leaked memory'"
|
||||
complete -n "__fish_valgrind_skin memcheck" -xc valgrind -l leak-resolution -d (N_ "Determines how willing Memcheck is to consider different backtraces to be the same") -a "low\t'Two entries need to match' med\t'Four entries need to match' high\t'All entries need to match'"
|
||||
complete -n "__fish_valgrind_skin memcheck" -xc valgrind -l freelist-vol -d (N_ "Set size of freed memory pool")
|
||||
|
||||
@@ -40,10 +40,11 @@ if test "$USER" = root
|
||||
set path_list $path_list /sbin /usr/sbin /usr/local/sbin
|
||||
end
|
||||
|
||||
# Make a regular expressin that matches any component in the PATH. A
|
||||
# Make a regular expression that matches any component in the PATH. A
|
||||
# trailing slash is ok. The sed call is to remove the last '\|'.
|
||||
|
||||
set -l path_regexp \\\((printf "^%s\\(\\|/\\)\$\\|" $PATH | sed -e "s/..\$//")\\\)
|
||||
|
||||
set -l path_regexp \\\((printf "%s" \^$PATH'\(\|/\)$\|' | sed -e "s/..\$//")\\\)
|
||||
|
||||
for i in (printf "%s\n" $path_list|grep -v $path_regexp)
|
||||
if test -d $i
|
||||
|
||||
6
share/functions/N_.fish
Normal file
6
share/functions/N_.fish
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
function N_ -d "No-op"
|
||||
printf "%s" $argv
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ function cd -d (N_ "Change directory")
|
||||
end
|
||||
|
||||
# Avoid set completions
|
||||
set previous (command pwd)
|
||||
set previous $PWD
|
||||
|
||||
if test $argv[1] = - ^/dev/null
|
||||
if test $__fish_cd_direction = next ^/dev/null
|
||||
@@ -24,7 +24,7 @@ function cd -d (N_ "Change directory")
|
||||
|
||||
builtin cd $argv[1]
|
||||
|
||||
if test $status = 0 -a (command pwd) != $previous
|
||||
if test $status = 0 -a $PWD != $previous
|
||||
set -g dirprev $dirprev $previous
|
||||
set -e dirnext
|
||||
set -g __fish_cd_direction prev
|
||||
|
||||
@@ -74,7 +74,12 @@ function help -d (N_ "Show help for the fish shell")
|
||||
set fish_help_page "index.html\#expand"
|
||||
case (builtin -n)
|
||||
set fish_help_page "builtins.html\#$fish_help_item"
|
||||
case contains count dirh dirs help mimedb nextd open popd prevd pushd set_color tokenize psub umask type vared
|
||||
|
||||
# This command substitution should locate all commands with
|
||||
# documentation. It's a bit of a hack, since it relies on the
|
||||
# Doxygen markup format to never change...
|
||||
|
||||
case (sed -n < /usr/share/doc/fish-1.21.7/commands.html -e "s/.*<h2><a class=\"anchor\" name=\"\([^\"]*\)\">.*/\1/p")
|
||||
set fish_help_page "commands.html\#$fish_help_item"
|
||||
case $help_topics
|
||||
set fish_help_page "index.html\#$fish_help_item"
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
#
|
||||
|
||||
function pwd -d (N_ "Print working directory")
|
||||
command pwd | sed -e 's|/private||' -e "s|^$HOME|~|"
|
||||
echo $PWD | sed -e 's|/private||' -e "s|^$HOME|~|"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user