mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 04:43:10 +00:00
Remove trailing whitespaces and change tabs to spaces
This commit is contained in:
parent
b79854ad1a
commit
47df1ae40a
140 changed files with 29549 additions and 29549 deletions
|
@ -1,3 +1,3 @@
|
||||||
24-01-2012 Jan Kanis
|
24-01-2012 Jan Kanis
|
||||||
* Added a changelog file
|
* Added a changelog file
|
||||||
* removed unescaping if the 'commandline' builtin is called without the -o (tokenise) flag
|
* removed unescaping if the 'commandline' builtin is called without the -o (tokenise) flag
|
||||||
|
|
20
autoload.cpp
20
autoload.cpp
|
@ -70,11 +70,11 @@ int autoload_t::unload( const wcstring &cmd )
|
||||||
|
|
||||||
int autoload_t::load( const wcstring &cmd, bool reload )
|
int autoload_t::load( const wcstring &cmd, bool reload )
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
CHECK_BLOCK( 0 );
|
CHECK_BLOCK( 0 );
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
env_var_t path_var = env_get_string( env_var_name );
|
env_var_t path_var = env_get_string( env_var_name );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Do we know where to look?
|
Do we know where to look?
|
||||||
|
@ -105,16 +105,16 @@ int autoload_t::load( const wcstring &cmd, bool reload )
|
||||||
|
|
||||||
/* Get the list of paths from which we will try to load */
|
/* Get the list of paths from which we will try to load */
|
||||||
std::vector<wcstring> path_list;
|
std::vector<wcstring> path_list;
|
||||||
tokenize_variable_array( path_var, path_list );
|
tokenize_variable_array( path_var, path_list );
|
||||||
|
|
||||||
/* Try loading it */
|
/* Try loading it */
|
||||||
res = this->locate_file_and_maybe_load_it( cmd, true, reload, path_list );
|
res = this->locate_file_and_maybe_load_it( cmd, true, reload, path_list );
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
bool erased = !! is_loading_set.erase(cmd);
|
bool erased = !! is_loading_set.erase(cmd);
|
||||||
assert(erased);
|
assert(erased);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool autoload_t::can_load( const wcstring &cmd, const env_vars_snapshot_t &vars )
|
bool autoload_t::can_load( const wcstring &cmd, const env_vars_snapshot_t &vars )
|
||||||
|
@ -124,7 +124,7 @@ bool autoload_t::can_load( const wcstring &cmd, const env_vars_snapshot_t &vars
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<wcstring> path_list;
|
std::vector<wcstring> path_list;
|
||||||
tokenize_variable_array( path_var, path_list );
|
tokenize_variable_array( path_var, path_list );
|
||||||
return this->locate_file_and_maybe_load_it( cmd, false, false, path_list );
|
return this->locate_file_and_maybe_load_it( cmd, false, false, path_list );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
|
||||||
bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list )
|
bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list )
|
||||||
{
|
{
|
||||||
/* Note that we are NOT locked in this function! */
|
/* Note that we are NOT locked in this function! */
|
||||||
size_t i;
|
size_t i;
|
||||||
bool reloaded = 0;
|
bool reloaded = 0;
|
||||||
|
|
||||||
/* Try using a cached function. If we really want the function to be loaded, require that it be really loaded. If we're not reloading, allow stale functions. */
|
/* Try using a cached function. If we really want the function to be loaded, require that it be really loaded. If we're not reloading, allow stale functions. */
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,10 +58,10 @@ private:
|
||||||
/** The path from which we most recently autoloaded */
|
/** The path from which we most recently autoloaded */
|
||||||
wcstring last_path;
|
wcstring last_path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A table containing all the files that are currently being
|
A table containing all the files that are currently being
|
||||||
loaded. This is here to help prevent recursion.
|
loaded. This is here to help prevent recursion.
|
||||||
*/
|
*/
|
||||||
std::set<wcstring> is_loading_set;
|
std::set<wcstring> is_loading_set;
|
||||||
|
|
||||||
bool is_loading(const wcstring &name) const {
|
bool is_loading(const wcstring &name) const {
|
||||||
|
|
5022
builtin.cpp
5022
builtin.cpp
File diff suppressed because it is too large
Load diff
10
builtin.h
10
builtin.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file builtin.h
|
/** \file builtin.h
|
||||||
Prototypes for functions for executing builtin functions.
|
Prototypes for functions for executing builtin functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_BUILTIN_H
|
#ifndef FISH_BUILTIN_H
|
||||||
|
@ -15,9 +15,9 @@ class parser_t;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
COMMAND_NOT_BUILTIN,
|
COMMAND_NOT_BUILTIN,
|
||||||
BUILTIN_REGULAR,
|
BUILTIN_REGULAR,
|
||||||
BUILTIN_FUNCTION
|
BUILTIN_FUNCTION
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ enum
|
||||||
/**
|
/**
|
||||||
Error message for unknown switch
|
Error message for unknown switch
|
||||||
*/
|
*/
|
||||||
#define BUILTIN_ERR_UNKNOWN _( L"%ls: Unknown option '%ls'\n" )
|
#define BUILTIN_ERR_UNKNOWN _( L"%ls: Unknown option '%ls'\n" )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Error message for invalid character in variable name
|
Error message for invalid character in variable name
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
462
builtin_jobs.cpp
462
builtin_jobs.cpp
|
@ -1,5 +1,5 @@
|
||||||
/** \file builtin_jobs.c
|
/** \file builtin_jobs.c
|
||||||
Functions for executing the jobs builtin.
|
Functions for executing the jobs builtin.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -30,12 +30,12 @@
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
JOBS_DEFAULT, /**< Print lots of general info */
|
JOBS_DEFAULT, /**< Print lots of general info */
|
||||||
JOBS_PRINT_PID, /**< Print pid of each process in job */
|
JOBS_PRINT_PID, /**< Print pid of each process in job */
|
||||||
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
|
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
|
||||||
JOBS_PRINT_GROUP, /**< Print group id of job */
|
JOBS_PRINT_GROUP, /**< Print group id of job */
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,26 +45,26 @@ enum
|
||||||
*/
|
*/
|
||||||
static int cpu_use( const job_t *j )
|
static int cpu_use( const job_t *j )
|
||||||
{
|
{
|
||||||
double u=0;
|
double u=0;
|
||||||
process_t *p;
|
process_t *p;
|
||||||
|
|
||||||
for( p=j->first_process; p; p=p->next )
|
for( p=j->first_process; p; p=p->next )
|
||||||
{
|
{
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
int jiffies;
|
int jiffies;
|
||||||
gettimeofday( &t, 0 );
|
gettimeofday( &t, 0 );
|
||||||
jiffies = proc_get_jiffies( p );
|
jiffies = proc_get_jiffies( p );
|
||||||
|
|
||||||
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
|
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
|
||||||
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
|
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
|
||||||
|
|
||||||
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
|
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
|
||||||
t1, t2, jiffies, p->last_jiffies );
|
t1, t2, jiffies, p->last_jiffies );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
|
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
|
||||||
}
|
}
|
||||||
return u*1000000;
|
return u*1000000;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -73,83 +73,83 @@ static int cpu_use( const job_t *j )
|
||||||
*/
|
*/
|
||||||
static void builtin_jobs_print( const job_t *j, int mode, int header )
|
static void builtin_jobs_print( const job_t *j, int mode, int header )
|
||||||
{
|
{
|
||||||
process_t *p;
|
process_t *p;
|
||||||
switch( mode )
|
switch( mode )
|
||||||
{
|
{
|
||||||
case JOBS_DEFAULT:
|
case JOBS_DEFAULT:
|
||||||
{
|
{
|
||||||
|
|
||||||
if( header )
|
if( header )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Print table header before first job
|
Print table header before first job
|
||||||
*/
|
*/
|
||||||
stdout_buffer.append( _( L"Job\tGroup\t" ));
|
stdout_buffer.append( _( L"Job\tGroup\t" ));
|
||||||
#ifdef HAVE__PROC_SELF_STAT
|
#ifdef HAVE__PROC_SELF_STAT
|
||||||
stdout_buffer.append( _( L"CPU\t" ) );
|
stdout_buffer.append( _( L"CPU\t" ) );
|
||||||
#endif
|
#endif
|
||||||
stdout_buffer.append( _( L"State\tCommand\n" ) );
|
stdout_buffer.append( _( L"State\tCommand\n" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
append_format(stdout_buffer, L"%d\t%d\t", j->job_id, j->pgid );
|
append_format(stdout_buffer, L"%d\t%d\t", j->job_id, j->pgid );
|
||||||
|
|
||||||
#ifdef HAVE__PROC_SELF_STAT
|
#ifdef HAVE__PROC_SELF_STAT
|
||||||
append_format(stdout_buffer, L"%d%%\t", cpu_use(j) );
|
append_format(stdout_buffer, L"%d%%\t", cpu_use(j) );
|
||||||
#endif
|
#endif
|
||||||
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
|
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
|
||||||
stdout_buffer.append(L"\t");
|
stdout_buffer.append(L"\t");
|
||||||
stdout_buffer.append(j->command_wcstr());
|
stdout_buffer.append(j->command_wcstr());
|
||||||
stdout_buffer.append(L"\n");
|
stdout_buffer.append(L"\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JOBS_PRINT_GROUP:
|
case JOBS_PRINT_GROUP:
|
||||||
{
|
{
|
||||||
if( header )
|
if( header )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Print table header before first job
|
Print table header before first job
|
||||||
*/
|
*/
|
||||||
stdout_buffer.append( _( L"Group\n" ));
|
stdout_buffer.append( _( L"Group\n" ));
|
||||||
}
|
}
|
||||||
append_format(stdout_buffer, L"%d\n", j->pgid );
|
append_format(stdout_buffer, L"%d\n", j->pgid );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JOBS_PRINT_PID:
|
case JOBS_PRINT_PID:
|
||||||
{
|
{
|
||||||
if( header )
|
if( header )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Print table header before first job
|
Print table header before first job
|
||||||
*/
|
*/
|
||||||
stdout_buffer.append( _( L"Procces\n" ));
|
stdout_buffer.append( _( L"Procces\n" ));
|
||||||
}
|
}
|
||||||
|
|
||||||
for( p=j->first_process; p; p=p->next )
|
for( p=j->first_process; p; p=p->next )
|
||||||
{
|
{
|
||||||
append_format(stdout_buffer, L"%d\n", p->pid );
|
append_format(stdout_buffer, L"%d\n", p->pid );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JOBS_PRINT_COMMAND:
|
case JOBS_PRINT_COMMAND:
|
||||||
{
|
{
|
||||||
if( header )
|
if( header )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Print table header before first job
|
Print table header before first job
|
||||||
*/
|
*/
|
||||||
stdout_buffer.append( _( L"Command\n" ));
|
stdout_buffer.append( _( L"Command\n" ));
|
||||||
}
|
}
|
||||||
|
|
||||||
for( p=j->first_process; p; p=p->next )
|
for( p=j->first_process; p; p=p->next )
|
||||||
{
|
{
|
||||||
append_format(stdout_buffer, L"%ls\n", p->argv0() );
|
append_format(stdout_buffer, L"%ls\n", p->argv0() );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,192 +160,192 @@ static void builtin_jobs_print( const job_t *j, int mode, int header )
|
||||||
*/
|
*/
|
||||||
static int builtin_jobs( parser_t &parser, wchar_t **argv )
|
static int builtin_jobs( parser_t &parser, wchar_t **argv )
|
||||||
{
|
{
|
||||||
int argc=0;
|
int argc=0;
|
||||||
int found=0;
|
int found=0;
|
||||||
int mode=JOBS_DEFAULT;
|
int mode=JOBS_DEFAULT;
|
||||||
int print_last = 0;
|
int print_last = 0;
|
||||||
const job_t *j;
|
const job_t *j;
|
||||||
|
|
||||||
argc = builtin_count_args( argv );
|
argc = builtin_count_args( argv );
|
||||||
woptind=0;
|
woptind=0;
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
static const struct woption
|
static const struct woption
|
||||||
long_options[] =
|
long_options[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
L"pid", no_argument, 0, 'p'
|
L"pid", no_argument, 0, 'p'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"command", no_argument, 0, 'c'
|
L"command", no_argument, 0, 'c'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"group", no_argument, 0, 'g'
|
L"group", no_argument, 0, 'g'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"last", no_argument, 0, 'l'
|
L"last", no_argument, 0, 'l'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"help", no_argument, 0, 'h'
|
L"help", no_argument, 0, 'h'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int opt = wgetopt_long( argc,
|
int opt = wgetopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
L"pclgh",
|
L"pclgh",
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if(long_options[opt_index].flag != 0)
|
if(long_options[opt_index].flag != 0)
|
||||||
break;
|
break;
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
BUILTIN_ERR_UNKNOWN,
|
BUILTIN_ERR_UNKNOWN,
|
||||||
argv[0],
|
argv[0],
|
||||||
long_options[opt_index].name );
|
long_options[opt_index].name );
|
||||||
|
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
mode=JOBS_PRINT_PID;
|
mode=JOBS_PRINT_PID;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
mode=JOBS_PRINT_COMMAND;
|
mode=JOBS_PRINT_COMMAND;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
mode=JOBS_PRINT_GROUP;
|
mode=JOBS_PRINT_GROUP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
{
|
||||||
print_last = 1;
|
print_last = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
builtin_print_help( parser, argv[0], stdout_buffer );
|
builtin_print_help( parser, argv[0], stdout_buffer );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
|
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Do not babble if not interactive
|
Do not babble if not interactive
|
||||||
*/
|
*/
|
||||||
if( builtin_out_redirect )
|
if( builtin_out_redirect )
|
||||||
{
|
{
|
||||||
found=1;
|
found=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( print_last )
|
if( print_last )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Ignore unconstructed jobs, i.e. ourself.
|
Ignore unconstructed jobs, i.e. ourself.
|
||||||
*/
|
*/
|
||||||
job_iterator_t jobs;
|
job_iterator_t jobs;
|
||||||
const job_t *j;
|
const job_t *j;
|
||||||
while ((j = jobs.next()))
|
while ((j = jobs.next()))
|
||||||
{
|
{
|
||||||
|
|
||||||
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
||||||
{
|
{
|
||||||
builtin_jobs_print( j, mode, !found );
|
builtin_jobs_print( j, mode, !found );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( woptind < argc )
|
if( woptind < argc )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
found = 1;
|
found = 1;
|
||||||
|
|
||||||
for( i=woptind; i<argc; i++ )
|
for( i=woptind; i<argc; i++ )
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
wchar_t *end;
|
wchar_t *end;
|
||||||
errno=0;
|
errno=0;
|
||||||
pid=fish_wcstoi( argv[i], &end, 10 );
|
pid=fish_wcstoi( argv[i], &end, 10 );
|
||||||
if( errno || *end )
|
if( errno || *end )
|
||||||
{
|
{
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
_( L"%ls: '%ls' is not a job\n" ),
|
_( L"%ls: '%ls' is not a job\n" ),
|
||||||
argv[0],
|
argv[0],
|
||||||
argv[i] );
|
argv[i] );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
j = job_get_from_pid( pid );
|
j = job_get_from_pid( pid );
|
||||||
|
|
||||||
if( j && !job_is_completed( j ) )
|
if( j && !job_is_completed( j ) )
|
||||||
{
|
{
|
||||||
builtin_jobs_print( j, mode, !found );
|
builtin_jobs_print( j, mode, !found );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
_( L"%ls: No suitable job: %d\n" ),
|
_( L"%ls: No suitable job: %d\n" ),
|
||||||
argv[0],
|
argv[0],
|
||||||
pid );
|
pid );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
job_iterator_t jobs;
|
job_iterator_t jobs;
|
||||||
const job_t *j;
|
const job_t *j;
|
||||||
while ((j = jobs.next()))
|
while ((j = jobs.next()))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Ignore unconstructed jobs, i.e. ourself.
|
Ignore unconstructed jobs, i.e. ourself.
|
||||||
*/
|
*/
|
||||||
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
|
||||||
{
|
{
|
||||||
builtin_jobs_print( j, mode, !found );
|
builtin_jobs_print( j, mode, !found );
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !found )
|
if( !found )
|
||||||
{
|
{
|
||||||
append_format(stdout_buffer,
|
append_format(stdout_buffer,
|
||||||
_( L"%ls: There are no jobs\n" ),
|
_( L"%ls: There are no jobs\n" ),
|
||||||
argv[0] );
|
argv[0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1004
builtin_set.cpp
1004
builtin_set.cpp
File diff suppressed because it is too large
Load diff
|
@ -27,99 +27,99 @@ Functions used for implementing the ulimit builtin.
|
||||||
*/
|
*/
|
||||||
struct resource_t
|
struct resource_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Resource id
|
Resource id
|
||||||
*/
|
*/
|
||||||
int resource;
|
int resource;
|
||||||
/**
|
/**
|
||||||
Description of resource
|
Description of resource
|
||||||
*/
|
*/
|
||||||
const wchar_t *desc;
|
const wchar_t *desc;
|
||||||
/**
|
/**
|
||||||
Switch used on commandline to specify resource
|
Switch used on commandline to specify resource
|
||||||
*/
|
*/
|
||||||
wchar_t switch_char;
|
wchar_t switch_char;
|
||||||
/**
|
/**
|
||||||
The implicit multiplier used when setting getting values
|
The implicit multiplier used when setting getting values
|
||||||
*/
|
*/
|
||||||
int multiplier;
|
int multiplier;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Array of resource_t structs, describing all known resource types.
|
Array of resource_t structs, describing all known resource types.
|
||||||
*/
|
*/
|
||||||
static const struct resource_t resource_arr[] =
|
static const struct resource_t resource_arr[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024
|
RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
RLIMIT_DATA, L"Maximum size of a process’s data segment", L'd', 1024
|
RLIMIT_DATA, L"Maximum size of a process’s data segment", L'd', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
|
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#ifdef RLIMIT_MEMLOCK
|
#ifdef RLIMIT_MEMLOCK
|
||||||
{
|
{
|
||||||
RLIMIT_MEMLOCK, L"Maximum size that may be locked into memory", L'l', 1024
|
RLIMIT_MEMLOCK, L"Maximum size that may be locked into memory", L'l', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_RSS
|
#ifdef RLIMIT_RSS
|
||||||
{
|
{
|
||||||
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
|
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1
|
RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
RLIMIT_STACK, L"Maximum stack size", L's', 1024
|
RLIMIT_STACK, L"Maximum stack size", L's', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
|
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#ifdef RLIMIT_NPROC
|
#ifdef RLIMIT_NPROC
|
||||||
{
|
{
|
||||||
RLIMIT_NPROC, L"Maximum number of processes available to a single user", L'u', 1
|
RLIMIT_NPROC, L"Maximum number of processes available to a single user", L'u', 1
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#endif
|
#endif
|
||||||
#ifdef RLIMIT_AS
|
#ifdef RLIMIT_AS
|
||||||
{
|
{
|
||||||
RLIMIT_AS, L"Maximum amount of virtual memory available to the shell", L'v', 1024
|
RLIMIT_AS, L"Maximum amount of virtual memory available to the shell", L'v', 1024
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the implicit multiplication factor for the specified resource limit
|
Get the implicit multiplication factor for the specified resource limit
|
||||||
*/
|
*/
|
||||||
static int get_multiplier( int what )
|
static int get_multiplier( int what )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i=0; resource_arr[i].desc; i++ )
|
for( i=0; resource_arr[i].desc; i++ )
|
||||||
{
|
{
|
||||||
if( resource_arr[i].resource == what )
|
if( resource_arr[i].resource == what )
|
||||||
{
|
{
|
||||||
return resource_arr[i].multiplier;
|
return resource_arr[i].multiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,11 +129,11 @@ static int get_multiplier( int what )
|
||||||
*/
|
*/
|
||||||
static rlim_t get( int resource, int hard )
|
static rlim_t get( int resource, int hard )
|
||||||
{
|
{
|
||||||
struct rlimit ls;
|
struct rlimit ls;
|
||||||
|
|
||||||
getrlimit( resource, &ls );
|
getrlimit( resource, &ls );
|
||||||
|
|
||||||
return hard ? ls.rlim_max:ls.rlim_cur;
|
return hard ? ls.rlim_max:ls.rlim_cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,12 +141,12 @@ static rlim_t get( int resource, int hard )
|
||||||
*/
|
*/
|
||||||
static void print( int resource, int hard )
|
static void print( int resource, int hard )
|
||||||
{
|
{
|
||||||
rlim_t l = get( resource, hard );
|
rlim_t l = get( resource, hard );
|
||||||
|
|
||||||
if( l == RLIM_INFINITY )
|
if( l == RLIM_INFINITY )
|
||||||
stdout_buffer.append( L"unlimited\n" );
|
stdout_buffer.append( L"unlimited\n" );
|
||||||
else
|
else
|
||||||
append_format(stdout_buffer, L"%d\n", l / get_multiplier( resource ) );
|
append_format(stdout_buffer, L"%d\n", l / get_multiplier( resource ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,39 +155,39 @@ static void print( int resource, int hard )
|
||||||
*/
|
*/
|
||||||
static void print_all( int hard )
|
static void print_all( int hard )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int w=0;
|
int w=0;
|
||||||
|
|
||||||
for( i=0; resource_arr[i].desc; i++ )
|
for( i=0; resource_arr[i].desc; i++ )
|
||||||
{
|
{
|
||||||
w=maxi( w, my_wcswidth(resource_arr[i].desc));
|
w=maxi( w, my_wcswidth(resource_arr[i].desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
for( i=0; resource_arr[i].desc; i++ )
|
for( i=0; resource_arr[i].desc; i++ )
|
||||||
{
|
{
|
||||||
struct rlimit ls;
|
struct rlimit ls;
|
||||||
rlim_t l;
|
rlim_t l;
|
||||||
getrlimit( resource_arr[i].resource, &ls );
|
getrlimit( resource_arr[i].resource, &ls );
|
||||||
l = hard ? ls.rlim_max:ls.rlim_cur;
|
l = hard ? ls.rlim_max:ls.rlim_cur;
|
||||||
|
|
||||||
const wchar_t *unit = ((resource_arr[i].resource==RLIMIT_CPU)?L"(seconds, ":(get_multiplier(resource_arr[i].resource)==1?L"(":L"(kB, "));
|
const wchar_t *unit = ((resource_arr[i].resource==RLIMIT_CPU)?L"(seconds, ":(get_multiplier(resource_arr[i].resource)==1?L"(":L"(kB, "));
|
||||||
|
|
||||||
append_format(stdout_buffer,
|
append_format(stdout_buffer,
|
||||||
L"%-*ls %10ls-%lc) ",
|
L"%-*ls %10ls-%lc) ",
|
||||||
w,
|
w,
|
||||||
resource_arr[i].desc,
|
resource_arr[i].desc,
|
||||||
unit,
|
unit,
|
||||||
resource_arr[i].switch_char);
|
resource_arr[i].switch_char);
|
||||||
|
|
||||||
if( l == RLIM_INFINITY )
|
if( l == RLIM_INFINITY )
|
||||||
{
|
{
|
||||||
stdout_buffer.append( L"unlimited\n" );
|
stdout_buffer.append( L"unlimited\n" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
append_format(stdout_buffer, L"%d\n", l/get_multiplier(resource_arr[i].resource) );
|
append_format(stdout_buffer, L"%d\n", l/get_multiplier(resource_arr[i].resource) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,16 +196,16 @@ static void print_all( int hard )
|
||||||
*/
|
*/
|
||||||
static const wchar_t *get_desc( int what )
|
static const wchar_t *get_desc( int what )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i=0; resource_arr[i].desc; i++ )
|
for( i=0; resource_arr[i].desc; i++ )
|
||||||
{
|
{
|
||||||
if( resource_arr[i].resource == what )
|
if( resource_arr[i].resource == what )
|
||||||
{
|
{
|
||||||
return resource_arr[i].desc;
|
return resource_arr[i].desc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return L"Not a resource";
|
return L"Not a resource";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -215,37 +215,37 @@ static const wchar_t *get_desc( int what )
|
||||||
*/
|
*/
|
||||||
static int set( int resource, int hard, int soft, rlim_t value )
|
static int set( int resource, int hard, int soft, rlim_t value )
|
||||||
{
|
{
|
||||||
struct rlimit ls;
|
struct rlimit ls;
|
||||||
getrlimit( resource, &ls );
|
getrlimit( resource, &ls );
|
||||||
|
|
||||||
if( hard )
|
if( hard )
|
||||||
{
|
{
|
||||||
ls.rlim_max = value;
|
ls.rlim_max = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( soft )
|
if( soft )
|
||||||
{
|
{
|
||||||
ls.rlim_cur = value;
|
ls.rlim_cur = value;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Do not attempt to set the soft limit higher than the hard limit
|
Do not attempt to set the soft limit higher than the hard limit
|
||||||
*/
|
*/
|
||||||
if( ( value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY ) ||
|
if( ( value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY ) ||
|
||||||
( value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max))
|
( value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max))
|
||||||
{
|
{
|
||||||
ls.rlim_cur = ls.rlim_max;
|
ls.rlim_cur = ls.rlim_max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( setrlimit( resource, &ls ) )
|
if( setrlimit( resource, &ls ) )
|
||||||
{
|
{
|
||||||
if( errno == EPERM )
|
if( errno == EPERM )
|
||||||
append_format(stderr_buffer, L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc( resource ) );
|
append_format(stderr_buffer, L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc( resource ) );
|
||||||
else
|
else
|
||||||
builtin_wperror( L"ulimit" );
|
builtin_wperror( L"ulimit" );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,259 +254,259 @@ static int set( int resource, int hard, int soft, rlim_t value )
|
||||||
*/
|
*/
|
||||||
static int builtin_ulimit( parser_t &parser, wchar_t ** argv )
|
static int builtin_ulimit( parser_t &parser, wchar_t ** argv )
|
||||||
{
|
{
|
||||||
int hard=0;
|
int hard=0;
|
||||||
int soft=0;
|
int soft=0;
|
||||||
|
|
||||||
int what = RLIMIT_FSIZE;
|
int what = RLIMIT_FSIZE;
|
||||||
int report_all = 0;
|
int report_all = 0;
|
||||||
|
|
||||||
int argc = builtin_count_args( argv );
|
int argc = builtin_count_args( argv );
|
||||||
|
|
||||||
woptind=0;
|
woptind=0;
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
static const struct woption
|
static const struct woption
|
||||||
long_options[] =
|
long_options[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
L"all", no_argument, 0, 'a'
|
L"all", no_argument, 0, 'a'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"hard", no_argument, 0, 'H'
|
L"hard", no_argument, 0, 'H'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"soft", no_argument, 0, 'S'
|
L"soft", no_argument, 0, 'S'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"core-size", no_argument, 0, 'c'
|
L"core-size", no_argument, 0, 'c'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"data-size", no_argument, 0, 'd'
|
L"data-size", no_argument, 0, 'd'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"file-size", no_argument, 0, 'f'
|
L"file-size", no_argument, 0, 'f'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"lock-size", no_argument, 0, 'l'
|
L"lock-size", no_argument, 0, 'l'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"resident-set-size", no_argument, 0, 'm'
|
L"resident-set-size", no_argument, 0, 'm'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"file-descriptor-count", no_argument, 0, 'n'
|
L"file-descriptor-count", no_argument, 0, 'n'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"stack-size", no_argument, 0, 's'
|
L"stack-size", no_argument, 0, 's'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"cpu-time", no_argument, 0, 't'
|
L"cpu-time", no_argument, 0, 't'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"process-count", no_argument, 0, 'u'
|
L"process-count", no_argument, 0, 'u'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"virtual-memory-size", no_argument, 0, 'v'
|
L"virtual-memory-size", no_argument, 0, 'v'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"help", no_argument, 0, 'h'
|
L"help", no_argument, 0, 'h'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int opt = wgetopt_long( argc,
|
int opt = wgetopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
L"aHScdflmnstuvh",
|
L"aHScdflmnstuvh",
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
if(long_options[opt_index].flag != 0)
|
if(long_options[opt_index].flag != 0)
|
||||||
break;
|
break;
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
BUILTIN_ERR_UNKNOWN,
|
BUILTIN_ERR_UNKNOWN,
|
||||||
argv[0],
|
argv[0],
|
||||||
long_options[opt_index].name );
|
long_options[opt_index].name );
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case L'a':
|
case L'a':
|
||||||
report_all=1;
|
report_all=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'H':
|
case L'H':
|
||||||
hard=1;
|
hard=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'S':
|
case L'S':
|
||||||
soft=1;
|
soft=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'c':
|
case L'c':
|
||||||
what=RLIMIT_CORE;
|
what=RLIMIT_CORE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'd':
|
case L'd':
|
||||||
what=RLIMIT_DATA;
|
what=RLIMIT_DATA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L'f':
|
case L'f':
|
||||||
what=RLIMIT_FSIZE;
|
what=RLIMIT_FSIZE;
|
||||||
break;
|
break;
|
||||||
#ifdef RLIMIT_MEMLOCK
|
#ifdef RLIMIT_MEMLOCK
|
||||||
case L'l':
|
case L'l':
|
||||||
what=RLIMIT_MEMLOCK;
|
what=RLIMIT_MEMLOCK;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RLIMIT_RSS
|
#ifdef RLIMIT_RSS
|
||||||
case L'm':
|
case L'm':
|
||||||
what=RLIMIT_RSS;
|
what=RLIMIT_RSS;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case L'n':
|
case L'n':
|
||||||
what=RLIMIT_NOFILE;
|
what=RLIMIT_NOFILE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L's':
|
case L's':
|
||||||
what=RLIMIT_STACK;
|
what=RLIMIT_STACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L't':
|
case L't':
|
||||||
what=RLIMIT_CPU;
|
what=RLIMIT_CPU;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef RLIMIT_NPROC
|
#ifdef RLIMIT_NPROC
|
||||||
case L'u':
|
case L'u':
|
||||||
what=RLIMIT_NPROC;
|
what=RLIMIT_NPROC;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RLIMIT_AS
|
#ifdef RLIMIT_AS
|
||||||
case L'v':
|
case L'v':
|
||||||
what=RLIMIT_AS;
|
what=RLIMIT_AS;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case L'h':
|
case L'h':
|
||||||
builtin_print_help( parser, argv[0], stdout_buffer );
|
builtin_print_help( parser, argv[0], stdout_buffer );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case L'?':
|
case L'?':
|
||||||
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
|
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( report_all )
|
if( report_all )
|
||||||
{
|
{
|
||||||
if( argc - woptind == 0 )
|
if( argc - woptind == 0 )
|
||||||
{
|
{
|
||||||
print_all( hard );
|
print_all( hard );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stderr_buffer.append(argv[0]);
|
stderr_buffer.append(argv[0]);
|
||||||
stderr_buffer.append(L": Too many arguments\n");
|
stderr_buffer.append(L": Too many arguments\n");
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( argc - woptind )
|
switch( argc - woptind )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Show current limit value
|
Show current limit value
|
||||||
*/
|
*/
|
||||||
print( what, hard );
|
print( what, hard );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Change current limit value
|
Change current limit value
|
||||||
*/
|
*/
|
||||||
rlim_t new_limit;
|
rlim_t new_limit;
|
||||||
wchar_t *end;
|
wchar_t *end;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set both hard and soft limits if nothing else was specified
|
Set both hard and soft limits if nothing else was specified
|
||||||
*/
|
*/
|
||||||
if( !(hard+soft) )
|
if( !(hard+soft) )
|
||||||
{
|
{
|
||||||
hard=soft=1;
|
hard=soft=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( wcscasecmp( argv[woptind], L"unlimited" )==0)
|
if( wcscasecmp( argv[woptind], L"unlimited" )==0)
|
||||||
{
|
{
|
||||||
new_limit = RLIM_INFINITY;
|
new_limit = RLIM_INFINITY;
|
||||||
}
|
}
|
||||||
else if( wcscasecmp( argv[woptind], L"hard" )==0)
|
else if( wcscasecmp( argv[woptind], L"hard" )==0)
|
||||||
{
|
{
|
||||||
new_limit = get( what, 1 );
|
new_limit = get( what, 1 );
|
||||||
}
|
}
|
||||||
else if( wcscasecmp( argv[woptind], L"soft" )==0)
|
else if( wcscasecmp( argv[woptind], L"soft" )==0)
|
||||||
{
|
{
|
||||||
new_limit = get( what, soft );
|
new_limit = get( what, soft );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errno=0;
|
errno=0;
|
||||||
new_limit = wcstol( argv[woptind], &end, 10 );
|
new_limit = wcstol( argv[woptind], &end, 10 );
|
||||||
if( errno || *end )
|
if( errno || *end )
|
||||||
{
|
{
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
L"%ls: Invalid limit '%ls'\n",
|
L"%ls: Invalid limit '%ls'\n",
|
||||||
argv[0],
|
argv[0],
|
||||||
argv[woptind] );
|
argv[woptind] );
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
new_limit *= get_multiplier( what );
|
new_limit *= get_multiplier( what );
|
||||||
}
|
}
|
||||||
|
|
||||||
return set( what, hard, soft, new_limit );
|
return set( what, hard, soft, new_limit );
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
stderr_buffer.append(argv[0]);
|
stderr_buffer.append(argv[0]);
|
||||||
stderr_buffer.append(L": Too many arguments\n");
|
stderr_buffer.append(L": Too many arguments\n");
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
2146
common.cpp
2146
common.cpp
File diff suppressed because it is too large
Load diff
80
common.h
80
common.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file common.h
|
/** \file common.h
|
||||||
Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
|
Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_COMMON_H
|
#ifndef FISH_COMMON_H
|
||||||
|
@ -85,7 +85,7 @@ typedef unsigned int escape_flags_t;
|
||||||
void exit_without_destructors(int code) __attribute__ ((noreturn));
|
void exit_without_destructors(int code) __attribute__ ((noreturn));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Save the shell mode on startup so we can restore them on exit
|
Save the shell mode on startup so we can restore them on exit
|
||||||
*/
|
*/
|
||||||
extern struct termios shell_modes;
|
extern struct termios shell_modes;
|
||||||
|
|
||||||
|
@ -118,56 +118,56 @@ extern const wchar_t *program_name;
|
||||||
failiure, the current function is ended at once. The second
|
failiure, the current function is ended at once. The second
|
||||||
parameter is the return value of the current function on failiure.
|
parameter is the return value of the current function on failiure.
|
||||||
*/
|
*/
|
||||||
#define CHECK( arg, retval ) \
|
#define CHECK( arg, retval ) \
|
||||||
if( !(arg) ) \
|
if( !(arg) ) \
|
||||||
{ \
|
{ \
|
||||||
debug( 0, \
|
debug( 0, \
|
||||||
"function %s called with null value for argument %s. ", \
|
"function %s called with null value for argument %s. ", \
|
||||||
__func__, \
|
__func__, \
|
||||||
#arg ); \
|
#arg ); \
|
||||||
bugreport(); \
|
bugreport(); \
|
||||||
show_stackframe(); \
|
show_stackframe(); \
|
||||||
return retval; \
|
return retval; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Pause for input, then exit the program. If supported, print a backtrace first.
|
Pause for input, then exit the program. If supported, print a backtrace first.
|
||||||
*/
|
*/
|
||||||
#define FATAL_EXIT() \
|
#define FATAL_EXIT() \
|
||||||
{ \
|
{ \
|
||||||
char exit_read_buff; \
|
char exit_read_buff; \
|
||||||
show_stackframe(); \
|
show_stackframe(); \
|
||||||
read( 0, &exit_read_buff, 1 ); \
|
read( 0, &exit_read_buff, 1 ); \
|
||||||
exit_without_destructors( 1 ); \
|
exit_without_destructors( 1 ); \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Exit program at once, leaving an error message about running out of memory.
|
Exit program at once, leaving an error message about running out of memory.
|
||||||
*/
|
*/
|
||||||
#define DIE_MEM() \
|
#define DIE_MEM() \
|
||||||
{ \
|
{ \
|
||||||
fwprintf( stderr, \
|
fwprintf( stderr, \
|
||||||
L"fish: Out of memory on line %ld of file %s, shutting down fish\n", \
|
L"fish: Out of memory on line %ld of file %s, shutting down fish\n", \
|
||||||
(long)__LINE__, \
|
(long)__LINE__, \
|
||||||
__FILE__ ); \
|
__FILE__ ); \
|
||||||
FATAL_EXIT(); \
|
FATAL_EXIT(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check if signals are blocked. If so, print an error message and
|
Check if signals are blocked. If so, print an error message and
|
||||||
return from the function performing this check.
|
return from the function performing this check.
|
||||||
*/
|
*/
|
||||||
#define CHECK_BLOCK( retval ) \
|
#define CHECK_BLOCK( retval ) \
|
||||||
if( signal_is_blocked() ) \
|
if( signal_is_blocked() ) \
|
||||||
{ \
|
{ \
|
||||||
debug( 0, \
|
debug( 0, \
|
||||||
"function %s called while blocking signals. ", \
|
"function %s called while blocking signals. ", \
|
||||||
__func__); \
|
__func__); \
|
||||||
bugreport(); \
|
bugreport(); \
|
||||||
show_stackframe(); \
|
show_stackframe(); \
|
||||||
return retval; \
|
return retval; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Shorthand for wgettext call
|
Shorthand for wgettext call
|
||||||
|
@ -651,7 +651,7 @@ wcstring escape_string( const wcstring &in, escape_flags_t flags );
|
||||||
|
|
||||||
*/
|
*/
|
||||||
wchar_t *unescape( const wchar_t * in,
|
wchar_t *unescape( const wchar_t * in,
|
||||||
int escape_special );
|
int escape_special );
|
||||||
|
|
||||||
bool unescape_string( wcstring &str,
|
bool unescape_string( wcstring &str,
|
||||||
int escape_special );
|
int escape_special );
|
||||||
|
@ -717,7 +717,7 @@ void bugreport();
|
||||||
double timef();
|
double timef();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Call the following function early in main to set the main thread.
|
Call the following function early in main to set the main thread.
|
||||||
This is our replacement for pthread_main_np().
|
This is our replacement for pthread_main_np().
|
||||||
*/
|
*/
|
||||||
void set_main_thread();
|
void set_main_thread();
|
||||||
|
|
1732
complete.cpp
1732
complete.cpp
File diff suppressed because it is too large
Load diff
76
complete.h
76
complete.h
|
@ -1,8 +1,8 @@
|
||||||
/** \file complete.h
|
/** \file complete.h
|
||||||
Prototypes for functions related to tab-completion.
|
Prototypes for functions related to tab-completion.
|
||||||
|
|
||||||
These functions are used for storing and retrieving tab-completion
|
These functions are used for storing and retrieving tab-completion
|
||||||
data, as well as for performing tab-completion.
|
data, as well as for performing tab-completion.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_COMPLETE_H
|
#ifndef FISH_COMPLETE_H
|
||||||
|
@ -18,39 +18,39 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
/**
|
/**
|
||||||
Use all completions
|
Use all completions
|
||||||
*/
|
*/
|
||||||
#define SHARED 0
|
#define SHARED 0
|
||||||
/**
|
/**
|
||||||
Do not use file completion
|
Do not use file completion
|
||||||
*/
|
*/
|
||||||
#define NO_FILES 1
|
#define NO_FILES 1
|
||||||
/**
|
/**
|
||||||
Require a parameter after completion
|
Require a parameter after completion
|
||||||
*/
|
*/
|
||||||
#define NO_COMMON 2
|
#define NO_COMMON 2
|
||||||
/**
|
/**
|
||||||
Only use the argument list specifies with completion after
|
Only use the argument list specifies with completion after
|
||||||
option. This is the same as (NO_FILES & NO_COMMON)
|
option. This is the same as (NO_FILES & NO_COMMON)
|
||||||
*/
|
*/
|
||||||
#define EXCLUSIVE 3
|
#define EXCLUSIVE 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Command is a path
|
Command is a path
|
||||||
*/
|
*/
|
||||||
#define PATH 1
|
#define PATH 1
|
||||||
/**
|
/**
|
||||||
Command is not a path
|
Command is not a path
|
||||||
*/
|
*/
|
||||||
#define COMMAND 0
|
#define COMMAND 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Separator between completion and description
|
Separator between completion and description
|
||||||
*/
|
*/
|
||||||
#define COMPLETE_SEP L'\004'
|
#define COMPLETE_SEP L'\004'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Separator between completion and description
|
Separator between completion and description
|
||||||
*/
|
*/
|
||||||
#define COMPLETE_SEP_STR L"\004"
|
#define COMPLETE_SEP_STR L"\004"
|
||||||
|
|
||||||
|
@ -109,30 +109,30 @@ class completion_t
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* No public default constructor */
|
/* No public default constructor */
|
||||||
completion_t();
|
completion_t();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The completion string
|
The completion string
|
||||||
*/
|
*/
|
||||||
wcstring completion;
|
wcstring completion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The description for this completion
|
The description for this completion
|
||||||
*/
|
*/
|
||||||
wcstring description;
|
wcstring description;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flags determining the completion behaviour.
|
Flags determining the completion behaviour.
|
||||||
|
|
||||||
Determines whether a space should be inserted after this
|
Determines whether a space should be inserted after this
|
||||||
compeltion if it is the only possible completion using the
|
compeltion if it is the only possible completion using the
|
||||||
COMPLETE_NO_SPACE flag.
|
COMPLETE_NO_SPACE flag.
|
||||||
|
|
||||||
The COMPLETE_NO_CASE can be used to signal that this completion
|
The COMPLETE_NO_CASE can be used to signal that this completion
|
||||||
is case insensitive.
|
is case insensitive.
|
||||||
*/
|
*/
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
bool is_case_insensitive() const { return !! (flags & COMPLETE_NO_CASE); }
|
bool is_case_insensitive() const { return !! (flags & COMPLETE_NO_CASE); }
|
||||||
|
|
||||||
|
@ -142,9 +142,9 @@ public:
|
||||||
completion_t &operator=(const completion_t &);
|
completion_t &operator=(const completion_t &);
|
||||||
|
|
||||||
/* The following are needed for sorting and uniquing completions */
|
/* The following are needed for sorting and uniquing completions */
|
||||||
bool operator < (const completion_t& rhs) const;
|
bool operator < (const completion_t& rhs) const;
|
||||||
bool operator == (const completion_t& rhs) const;
|
bool operator == (const completion_t& rhs) const;
|
||||||
bool operator != (const completion_t& rhs) const;
|
bool operator != (const completion_t& rhs) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum complete_type_t {
|
enum complete_type_t {
|
||||||
|
@ -240,17 +240,17 @@ void complete_print( wcstring &out );
|
||||||
Tests if the specified option is defined for the specified command
|
Tests if the specified option is defined for the specified command
|
||||||
*/
|
*/
|
||||||
int complete_is_valid_option( const wcstring &str,
|
int complete_is_valid_option( const wcstring &str,
|
||||||
const wcstring &opt,
|
const wcstring &opt,
|
||||||
wcstring_list_t *inErrorsOrNull,
|
wcstring_list_t *inErrorsOrNull,
|
||||||
bool allow_autoload );
|
bool allow_autoload );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tests if the specified argument is valid for the specified option
|
Tests if the specified argument is valid for the specified option
|
||||||
and command
|
and command
|
||||||
*/
|
*/
|
||||||
bool complete_is_valid_argument( const wcstring &str,
|
bool complete_is_valid_argument( const wcstring &str,
|
||||||
const wcstring &opt,
|
const wcstring &opt,
|
||||||
const wcstring &arg );
|
const wcstring &arg );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
802
configure.ac
802
configure.ac
File diff suppressed because it is too large
Load diff
6
env.h
6
env.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file env.h
|
/** \file env.h
|
||||||
Prototypes for functions for setting and getting environment variables.
|
Prototypes for functions for setting and getting environment variables.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_ENV_H
|
#ifndef FISH_ENV_H
|
||||||
|
@ -47,8 +47,8 @@
|
||||||
Error code for trying to alter read-only variable
|
Error code for trying to alter read-only variable
|
||||||
*/
|
*/
|
||||||
enum{
|
enum{
|
||||||
ENV_PERM = 1,
|
ENV_PERM = 1,
|
||||||
ENV_INVALID
|
ENV_INVALID
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ void env_universal_barrier();
|
||||||
|
|
||||||
static int is_dead()
|
static int is_dead()
|
||||||
{
|
{
|
||||||
return env_universal_server.fd < 0;
|
return env_universal_server.fd < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,85 +81,85 @@ static int is_dead()
|
||||||
*/
|
*/
|
||||||
static int get_socket( int fork_ok )
|
static int get_socket( int fork_ok )
|
||||||
{
|
{
|
||||||
int s, len;
|
int s, len;
|
||||||
struct sockaddr_un local;
|
struct sockaddr_un local;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
wchar_t *wdir;
|
wchar_t *wdir;
|
||||||
wchar_t *wuname;
|
wchar_t *wuname;
|
||||||
char *dir =0, *uname=0;
|
char *dir =0, *uname=0;
|
||||||
|
|
||||||
get_socket_count++;
|
get_socket_count++;
|
||||||
wdir = path;
|
wdir = path;
|
||||||
wuname = user;
|
wuname = user;
|
||||||
|
|
||||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
{
|
{
|
||||||
wperror(L"socket");
|
wperror(L"socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( wdir )
|
if( wdir )
|
||||||
dir = wcs2str(wdir );
|
dir = wcs2str(wdir );
|
||||||
else
|
else
|
||||||
dir = strdup("/tmp");
|
dir = strdup("/tmp");
|
||||||
|
|
||||||
if( wuname )
|
if( wuname )
|
||||||
uname = wcs2str(wuname );
|
uname = wcs2str(wuname );
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
pw = getpwuid( getuid() );
|
pw = getpwuid( getuid() );
|
||||||
uname = strdup( pw->pw_name );
|
uname = strdup( pw->pw_name );
|
||||||
}
|
}
|
||||||
|
|
||||||
name = (char *)malloc( strlen(dir) +
|
name = (char *)malloc( strlen(dir) +
|
||||||
strlen(uname) +
|
strlen(uname) +
|
||||||
strlen(SOCK_FILENAME) +
|
strlen(SOCK_FILENAME) +
|
||||||
2 );
|
2 );
|
||||||
|
|
||||||
strcpy( name, dir );
|
strcpy( name, dir );
|
||||||
strcat( name, "/" );
|
strcat( name, "/" );
|
||||||
strcat( name, SOCK_FILENAME );
|
strcat( name, SOCK_FILENAME );
|
||||||
strcat( name, uname );
|
strcat( name, uname );
|
||||||
|
|
||||||
free( dir );
|
free( dir );
|
||||||
free( uname );
|
free( uname );
|
||||||
|
|
||||||
debug( 3, L"Connect to socket %s at fd %2", name, s );
|
debug( 3, L"Connect to socket %s at fd %2", name, s );
|
||||||
|
|
||||||
local.sun_family = AF_UNIX;
|
local.sun_family = AF_UNIX;
|
||||||
strcpy(local.sun_path, name );
|
strcpy(local.sun_path, name );
|
||||||
free( name );
|
free( name );
|
||||||
len = sizeof(local);
|
len = sizeof(local);
|
||||||
|
|
||||||
if( connect( s, (struct sockaddr *)&local, len) == -1 )
|
if( connect( s, (struct sockaddr *)&local, len) == -1 )
|
||||||
{
|
{
|
||||||
close( s );
|
close( s );
|
||||||
if( fork_ok && start_fishd )
|
if( fork_ok && start_fishd )
|
||||||
{
|
{
|
||||||
debug( 2, L"Could not connect to socket %d, starting fishd", s );
|
debug( 2, L"Could not connect to socket %d, starting fishd", s );
|
||||||
|
|
||||||
start_fishd();
|
start_fishd();
|
||||||
|
|
||||||
return get_socket( 0 );
|
return get_socket( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
debug( 1, L"Could not connect to universal variable server, already tried manual restart (or no command supplied). You will not be able to share variable values between fish sessions. Is fish properly installed?" );
|
debug( 1, L"Could not connect to universal variable server, already tried manual restart (or no command supplied). You will not be able to share variable values between fish sessions. Is fish properly installed?" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (fcntl( s, F_SETFL, O_NONBLOCK ) != 0) || (fcntl( s, F_SETFD, FD_CLOEXEC ) != 0) )
|
if( (fcntl( s, F_SETFL, O_NONBLOCK ) != 0) || (fcntl( s, F_SETFD, FD_CLOEXEC ) != 0) )
|
||||||
{
|
{
|
||||||
wperror( L"fcntl" );
|
wperror( L"fcntl" );
|
||||||
close( s );
|
close( s );
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug( 3, L"Connected to fd %d", s );
|
debug( 3, L"Connected to fd %d", s );
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,15 +167,15 @@ static int get_socket( int fork_ok )
|
||||||
*/
|
*/
|
||||||
static void callback( fish_message_type_t type, const wchar_t *name, const wchar_t *val )
|
static void callback( fish_message_type_t type, const wchar_t *name, const wchar_t *val )
|
||||||
{
|
{
|
||||||
if( type == BARRIER_REPLY )
|
if( type == BARRIER_REPLY )
|
||||||
{
|
{
|
||||||
barrier_reply = 1;
|
barrier_reply = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( external_callback )
|
if( external_callback )
|
||||||
external_callback( type, name, val );
|
external_callback( type, name, val );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,23 +184,23 @@ static void callback( fish_message_type_t type, const wchar_t *name, const wchar
|
||||||
*/
|
*/
|
||||||
static void check_connection()
|
static void check_connection()
|
||||||
{
|
{
|
||||||
if( !init )
|
if( !init )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( env_universal_server.killme )
|
if( env_universal_server.killme )
|
||||||
{
|
{
|
||||||
debug( 3, L"Lost connection to universal variable server." );
|
debug( 3, L"Lost connection to universal variable server." );
|
||||||
|
|
||||||
if( close( env_universal_server.fd ) )
|
if( close( env_universal_server.fd ) )
|
||||||
{
|
{
|
||||||
wperror( L"close" );
|
wperror( L"close" );
|
||||||
}
|
}
|
||||||
|
|
||||||
env_universal_server.fd = -1;
|
env_universal_server.fd = -1;
|
||||||
env_universal_server.killme=0;
|
env_universal_server.killme=0;
|
||||||
env_universal_server.input.clear();
|
env_universal_server.input.clear();
|
||||||
env_universal_read_all();
|
env_universal_read_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,17 +208,17 @@ static void check_connection()
|
||||||
*/
|
*/
|
||||||
static void env_universal_remove_all()
|
static void env_universal_remove_all()
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
wcstring_list_t lst;
|
wcstring_list_t lst;
|
||||||
env_universal_common_get_names( lst,
|
env_universal_common_get_names( lst,
|
||||||
1,
|
1,
|
||||||
1 );
|
1 );
|
||||||
for( i=0; i<lst.size(); i++ )
|
for( i=0; i<lst.size(); i++ )
|
||||||
{
|
{
|
||||||
const wcstring &key = lst.at(i);
|
const wcstring &key = lst.at(i);
|
||||||
env_universal_common_remove( key );
|
env_universal_common_remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,63 +230,63 @@ static void env_universal_remove_all()
|
||||||
*/
|
*/
|
||||||
static void reconnect()
|
static void reconnect()
|
||||||
{
|
{
|
||||||
if( get_socket_count >= RECONNECT_COUNT )
|
if( get_socket_count >= RECONNECT_COUNT )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
debug( 3, L"Get new fishd connection" );
|
debug( 3, L"Get new fishd connection" );
|
||||||
|
|
||||||
init = 0;
|
init = 0;
|
||||||
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
|
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
|
||||||
env_universal_server.fd = get_socket(1);
|
env_universal_server.fd = get_socket(1);
|
||||||
init = 1;
|
init = 1;
|
||||||
if( env_universal_server.fd >= 0 )
|
if( env_universal_server.fd >= 0 )
|
||||||
{
|
{
|
||||||
env_universal_remove_all();
|
env_universal_remove_all();
|
||||||
env_universal_barrier();
|
env_universal_barrier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void env_universal_init( wchar_t * p,
|
void env_universal_init( wchar_t * p,
|
||||||
wchar_t *u,
|
wchar_t *u,
|
||||||
void (*sf)(),
|
void (*sf)(),
|
||||||
void (*cb)( fish_message_type_t type, const wchar_t *name, const wchar_t *val ))
|
void (*cb)( fish_message_type_t type, const wchar_t *name, const wchar_t *val ))
|
||||||
{
|
{
|
||||||
path=p;
|
path=p;
|
||||||
user=u;
|
user=u;
|
||||||
start_fishd=sf;
|
start_fishd=sf;
|
||||||
external_callback = cb;
|
external_callback = cb;
|
||||||
|
|
||||||
connection_init( &env_universal_server, -1 );
|
connection_init( &env_universal_server, -1 );
|
||||||
|
|
||||||
env_universal_server.fd = get_socket(1);
|
env_universal_server.fd = get_socket(1);
|
||||||
env_universal_common_init( &callback );
|
env_universal_common_init( &callback );
|
||||||
env_universal_read_all();
|
env_universal_read_all();
|
||||||
init = 1;
|
init = 1;
|
||||||
if( env_universal_server.fd >= 0 )
|
if( env_universal_server.fd >= 0 )
|
||||||
{
|
{
|
||||||
env_universal_barrier();
|
env_universal_barrier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_universal_destroy()
|
void env_universal_destroy()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Go into blocking mode and send all data before exiting
|
Go into blocking mode and send all data before exiting
|
||||||
*/
|
*/
|
||||||
if( env_universal_server.fd >= 0 )
|
if( env_universal_server.fd >= 0 )
|
||||||
{
|
{
|
||||||
if( fcntl( env_universal_server.fd, F_SETFL, 0 ) != 0 )
|
if( fcntl( env_universal_server.fd, F_SETFL, 0 ) != 0 )
|
||||||
{
|
{
|
||||||
wperror( L"fcntl" );
|
wperror( L"fcntl" );
|
||||||
}
|
}
|
||||||
try_send_all( &env_universal_server );
|
try_send_all( &env_universal_server );
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_destroy( &env_universal_server );
|
connection_destroy( &env_universal_server );
|
||||||
env_universal_server.fd =-1;
|
env_universal_server.fd =-1;
|
||||||
env_universal_common_destroy();
|
env_universal_common_destroy();
|
||||||
init = 0;
|
init = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -295,177 +295,177 @@ void env_universal_destroy()
|
||||||
*/
|
*/
|
||||||
int env_universal_read_all()
|
int env_universal_read_all()
|
||||||
{
|
{
|
||||||
if( !init)
|
if( !init)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( env_universal_server.fd == -1 )
|
if( env_universal_server.fd == -1 )
|
||||||
{
|
{
|
||||||
reconnect();
|
reconnect();
|
||||||
if( env_universal_server.fd == -1 )
|
if( env_universal_server.fd == -1 )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( env_universal_server.fd != -1 )
|
if( env_universal_server.fd != -1 )
|
||||||
{
|
{
|
||||||
read_message( &env_universal_server );
|
read_message( &env_universal_server );
|
||||||
check_connection();
|
check_connection();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug( 2, L"No connection to universal variable server" );
|
debug( 2, L"No connection to universal variable server" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t *env_universal_get( const wcstring &name )
|
wchar_t *env_universal_get( const wcstring &name )
|
||||||
{
|
{
|
||||||
if( !init)
|
if( !init)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return env_universal_common_get( name );
|
return env_universal_common_get( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
int env_universal_get_export( const wcstring &name )
|
int env_universal_get_export( const wcstring &name )
|
||||||
{
|
{
|
||||||
if( !init)
|
if( !init)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return env_universal_common_get_export( name );
|
return env_universal_common_get_export( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_universal_barrier()
|
void env_universal_barrier()
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
message_t *msg;
|
message_t *msg;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
|
||||||
if( !init || is_dead() )
|
if( !init || is_dead() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
barrier_reply = 0;
|
barrier_reply = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create barrier request
|
Create barrier request
|
||||||
*/
|
*/
|
||||||
msg= create_message( BARRIER, 0, 0);
|
msg= create_message( BARRIER, 0, 0);
|
||||||
msg->count=1;
|
msg->count=1;
|
||||||
env_universal_server.unsent->push(msg);
|
env_universal_server.unsent->push(msg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Wait until barrier request has been sent
|
Wait until barrier request has been sent
|
||||||
*/
|
*/
|
||||||
debug( 3, L"Create barrier" );
|
debug( 3, L"Create barrier" );
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
try_send_all( &env_universal_server );
|
try_send_all( &env_universal_server );
|
||||||
check_connection();
|
check_connection();
|
||||||
|
|
||||||
if( env_universal_server.unsent->empty() )
|
if( env_universal_server.unsent->empty() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if( env_universal_server.fd == -1 )
|
if( env_universal_server.fd == -1 )
|
||||||
{
|
{
|
||||||
reconnect();
|
reconnect();
|
||||||
debug( 2, L"barrier interrupted, exiting" );
|
debug( 2, L"barrier interrupted, exiting" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_ZERO( &fds );
|
FD_ZERO( &fds );
|
||||||
FD_SET( env_universal_server.fd, &fds );
|
FD_SET( env_universal_server.fd, &fds );
|
||||||
select( env_universal_server.fd+1, 0, &fds, 0, 0 );
|
select( env_universal_server.fd+1, 0, &fds, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Wait for barrier reply
|
Wait for barrier reply
|
||||||
*/
|
*/
|
||||||
debug( 3, L"Sent barrier request" );
|
debug( 3, L"Sent barrier request" );
|
||||||
while( !barrier_reply )
|
while( !barrier_reply )
|
||||||
{
|
{
|
||||||
if( env_universal_server.fd == -1 )
|
if( env_universal_server.fd == -1 )
|
||||||
{
|
{
|
||||||
reconnect();
|
reconnect();
|
||||||
debug( 2, L"barrier interrupted, exiting (2)" );
|
debug( 2, L"barrier interrupted, exiting (2)" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FD_ZERO( &fds );
|
FD_ZERO( &fds );
|
||||||
FD_SET( env_universal_server.fd, &fds );
|
FD_SET( env_universal_server.fd, &fds );
|
||||||
select( env_universal_server.fd+1, &fds, 0, 0, 0 );
|
select( env_universal_server.fd+1, &fds, 0, 0, 0 );
|
||||||
env_universal_read_all();
|
env_universal_read_all();
|
||||||
}
|
}
|
||||||
debug( 3, L"End barrier" );
|
debug( 3, L"End barrier" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void env_universal_set( const wcstring &name, const wcstring &value, int exportv )
|
void env_universal_set( const wcstring &name, const wcstring &value, int exportv )
|
||||||
{
|
{
|
||||||
message_t *msg;
|
message_t *msg;
|
||||||
|
|
||||||
if( !init )
|
if( !init )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
debug( 3, L"env_universal_set( \"%ls\", \"%ls\" )", name.c_str(), value.c_str() );
|
debug( 3, L"env_universal_set( \"%ls\", \"%ls\" )", name.c_str(), value.c_str() );
|
||||||
|
|
||||||
if( is_dead() )
|
if( is_dead() )
|
||||||
{
|
{
|
||||||
env_universal_common_set( name.c_str(), value.c_str(), exportv );
|
env_universal_common_set( name.c_str(), value.c_str(), exportv );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = create_message( exportv?SET_EXPORT:SET,
|
msg = create_message( exportv?SET_EXPORT:SET,
|
||||||
name.c_str(),
|
name.c_str(),
|
||||||
value.c_str());
|
value.c_str());
|
||||||
|
|
||||||
if( !msg )
|
if( !msg )
|
||||||
{
|
{
|
||||||
debug( 1, L"Could not create universal variable message" );
|
debug( 1, L"Could not create universal variable message" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->count=1;
|
msg->count=1;
|
||||||
env_universal_server.unsent->push(msg);
|
env_universal_server.unsent->push(msg);
|
||||||
env_universal_barrier();
|
env_universal_barrier();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int env_universal_remove( const wchar_t *name )
|
int env_universal_remove( const wchar_t *name )
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
message_t *msg;
|
message_t *msg;
|
||||||
if( !init )
|
if( !init )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
CHECK( name, 1 );
|
CHECK( name, 1 );
|
||||||
|
|
||||||
res = !env_universal_common_get( name );
|
res = !env_universal_common_get( name );
|
||||||
debug( 3,
|
debug( 3,
|
||||||
L"env_universal_remove( \"%ls\" )",
|
L"env_universal_remove( \"%ls\" )",
|
||||||
name );
|
name );
|
||||||
|
|
||||||
if( is_dead() )
|
if( is_dead() )
|
||||||
{
|
{
|
||||||
env_universal_common_remove( wcstring(name) );
|
env_universal_common_remove( wcstring(name) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg= create_message( ERASE, name, 0);
|
msg= create_message( ERASE, name, 0);
|
||||||
msg->count=1;
|
msg->count=1;
|
||||||
env_universal_server.unsent->push(msg);
|
env_universal_server.unsent->push(msg);
|
||||||
env_universal_barrier();
|
env_universal_barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_universal_get_names2( wcstring_list_t &lst,
|
void env_universal_get_names2( wcstring_list_t &lst,
|
||||||
int show_exported,
|
int show_exported,
|
||||||
int show_unexported )
|
int show_unexported )
|
||||||
{
|
{
|
||||||
if( !init )
|
if( !init )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
env_universal_common_get_names( lst,
|
env_universal_common_get_names( lst,
|
||||||
show_exported,
|
show_exported,
|
||||||
show_unexported );
|
show_unexported );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/** \file env_universal.h
|
/** \file env_universal.h
|
||||||
Universal variable client library.
|
Universal variable client library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ENV_UNIVERSAL_H
|
#ifndef ENV_UNIVERSAL_H
|
||||||
|
@ -61,8 +61,8 @@ int env_universal_read_all();
|
||||||
\param show_unexported whether unexported variables should be shown
|
\param show_unexported whether unexported variables should be shown
|
||||||
*/
|
*/
|
||||||
void env_universal_get_names2( wcstring_list_t &list,
|
void env_universal_get_names2( wcstring_list_t &list,
|
||||||
int show_exported,
|
int show_exported,
|
||||||
int show_unexported );
|
int show_unexported );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Synchronize with fishd
|
Synchronize with fishd
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,11 +42,11 @@
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
SET,
|
SET,
|
||||||
SET_EXPORT,
|
SET_EXPORT,
|
||||||
ERASE,
|
ERASE,
|
||||||
BARRIER,
|
BARRIER,
|
||||||
BARRIER_REPLY,
|
BARRIER_REPLY,
|
||||||
} fish_message_type_t;
|
} fish_message_type_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,15 +59,15 @@ typedef enum
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Number of queues that contain this message. Once this reaches zero, the message should be deleted
|
Number of queues that contain this message. Once this reaches zero, the message should be deleted
|
||||||
*/
|
*/
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Message body. The message must be allocated using enough memory to actually contain the message.
|
Message body. The message must be allocated using enough memory to actually contain the message.
|
||||||
*/
|
*/
|
||||||
std::string body;
|
std::string body;
|
||||||
|
|
||||||
} message_t;
|
} message_t;
|
||||||
|
|
||||||
|
@ -78,46 +78,46 @@ typedef std::queue<message_t *> message_queue_t;
|
||||||
*/
|
*/
|
||||||
typedef struct connection
|
typedef struct connection
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
The file descriptor this socket lives on
|
The file descriptor this socket lives on
|
||||||
*/
|
*/
|
||||||
int fd;
|
int fd;
|
||||||
/**
|
/**
|
||||||
Queue of onsent messages
|
Queue of onsent messages
|
||||||
*/
|
*/
|
||||||
message_queue_t *unsent;
|
message_queue_t *unsent;
|
||||||
/**
|
/**
|
||||||
Set to one when this connection should be killed
|
Set to one when this connection should be killed
|
||||||
*/
|
*/
|
||||||
int killme;
|
int killme;
|
||||||
/**
|
/**
|
||||||
The input string. Input from the socket goes here. When a
|
The input string. Input from the socket goes here. When a
|
||||||
newline is encountered, the buffer is parsed and cleared.
|
newline is encountered, the buffer is parsed and cleared.
|
||||||
*/
|
*/
|
||||||
std::vector<char> input;
|
std::vector<char> input;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The read buffer.
|
The read buffer.
|
||||||
*/
|
*/
|
||||||
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
|
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Number of bytes that have already been consumed.
|
Number of bytes that have already been consumed.
|
||||||
*/
|
*/
|
||||||
size_t buffer_consumed;
|
size_t buffer_consumed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Number of bytes that have been read into the buffer.
|
Number of bytes that have been read into the buffer.
|
||||||
*/
|
*/
|
||||||
size_t buffer_used;
|
size_t buffer_used;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Link to the next connection
|
Link to the next connection
|
||||||
*/
|
*/
|
||||||
struct connection *next;
|
struct connection *next;
|
||||||
}
|
}
|
||||||
connection_t;
|
connection_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read all available messages on this connection
|
Read all available messages on this connection
|
||||||
|
@ -151,8 +151,8 @@ void env_universal_common_destroy();
|
||||||
variables, it does not communicate with any other process.
|
variables, it does not communicate with any other process.
|
||||||
*/
|
*/
|
||||||
void env_universal_common_get_names( wcstring_list_t &lst,
|
void env_universal_common_get_names( wcstring_list_t &lst,
|
||||||
int show_exported,
|
int show_exported,
|
||||||
int show_unexported );
|
int show_unexported );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Perform the specified variable assignment.
|
Perform the specified variable assignment.
|
||||||
|
|
598
event.cpp
598
event.cpp
|
@ -1,6 +1,6 @@
|
||||||
/** \file event.c
|
/** \file event.c
|
||||||
|
|
||||||
Functions for handling event triggers
|
Functions for handling event triggers
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -36,20 +36,20 @@
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Number of delivered signals
|
Number of delivered signals
|
||||||
*/
|
*/
|
||||||
int count;
|
int count;
|
||||||
/**
|
/**
|
||||||
Whether signals have been skipped
|
Whether signals have been skipped
|
||||||
*/
|
*/
|
||||||
int overflow;
|
int overflow;
|
||||||
/**
|
/**
|
||||||
Array of signal events
|
Array of signal events
|
||||||
*/
|
*/
|
||||||
int signal[SIG_UNHANDLED_MAX];
|
int signal[SIG_UNHANDLED_MAX];
|
||||||
}
|
}
|
||||||
signal_list_t;
|
signal_list_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The signal event list. Actually two separate lists. One which is
|
The signal event list. Actually two separate lists. One which is
|
||||||
|
@ -90,48 +90,48 @@ static int event_match( const event_t *classv, const event_t *instance )
|
||||||
{
|
{
|
||||||
|
|
||||||
/* If the function names are both non-empty and different, then it's not a match */
|
/* If the function names are both non-empty and different, then it's not a match */
|
||||||
if( ! classv->function_name.empty() &&
|
if( ! classv->function_name.empty() &&
|
||||||
! instance->function_name.empty() &&
|
! instance->function_name.empty() &&
|
||||||
classv->function_name != instance->function_name)
|
classv->function_name != instance->function_name)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( classv->type == EVENT_ANY )
|
if( classv->type == EVENT_ANY )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if( classv->type != instance->type )
|
if( classv->type != instance->type )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
switch( classv->type )
|
switch( classv->type )
|
||||||
{
|
{
|
||||||
|
|
||||||
case EVENT_SIGNAL:
|
case EVENT_SIGNAL:
|
||||||
if( classv->param1.signal == EVENT_ANY_SIGNAL )
|
if( classv->param1.signal == EVENT_ANY_SIGNAL )
|
||||||
return 1;
|
return 1;
|
||||||
return classv->param1.signal == instance->param1.signal;
|
return classv->param1.signal == instance->param1.signal;
|
||||||
|
|
||||||
case EVENT_VARIABLE:
|
case EVENT_VARIABLE:
|
||||||
return instance->str_param1 == classv->str_param1;
|
return instance->str_param1 == classv->str_param1;
|
||||||
|
|
||||||
case EVENT_EXIT:
|
case EVENT_EXIT:
|
||||||
if( classv->param1.pid == EVENT_ANY_PID )
|
if( classv->param1.pid == EVENT_ANY_PID )
|
||||||
return 1;
|
return 1;
|
||||||
return classv->param1.pid == instance->param1.pid;
|
return classv->param1.pid == instance->param1.pid;
|
||||||
|
|
||||||
case EVENT_JOB_ID:
|
case EVENT_JOB_ID:
|
||||||
return classv->param1.job_id == instance->param1.job_id;
|
return classv->param1.job_id == instance->param1.job_id;
|
||||||
|
|
||||||
case EVENT_GENERIC:
|
case EVENT_GENERIC:
|
||||||
return instance->str_param1 == classv->str_param1;
|
return instance->str_param1 == classv->str_param1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This should never be reached
|
This should never be reached
|
||||||
*/
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,12 +144,12 @@ static event_t *event_copy( const event_t *event, int copy_arguments )
|
||||||
event_t *e = new event_t(*event);
|
event_t *e = new event_t(*event);
|
||||||
|
|
||||||
e->arguments.reset(new wcstring_list_t);
|
e->arguments.reset(new wcstring_list_t);
|
||||||
if( copy_arguments && event->arguments.get() != NULL )
|
if( copy_arguments && event->arguments.get() != NULL )
|
||||||
{
|
{
|
||||||
*(e->arguments) = *(event->arguments);
|
*(e->arguments) = *(event->arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,71 +157,71 @@ static event_t *event_copy( const event_t *event, int copy_arguments )
|
||||||
*/
|
*/
|
||||||
static int event_is_blocked( event_t *e )
|
static int event_is_blocked( event_t *e )
|
||||||
{
|
{
|
||||||
block_t *block;
|
block_t *block;
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
for( block = parser.current_block; block; block = block->outer )
|
for( block = parser.current_block; block; block = block->outer )
|
||||||
{
|
{
|
||||||
if (event_block_list_blocks_type(block->event_blocks, e->type))
|
if (event_block_list_blocks_type(block->event_blocks, e->type))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return event_block_list_blocks_type(parser.global_event_blocks, e->type);
|
return event_block_list_blocks_type(parser.global_event_blocks, e->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring event_get_desc( const event_t *e )
|
wcstring event_get_desc( const event_t *e )
|
||||||
{
|
{
|
||||||
|
|
||||||
CHECK( e, 0 );
|
CHECK( e, 0 );
|
||||||
|
|
||||||
wcstring result;
|
wcstring result;
|
||||||
switch( e->type )
|
switch( e->type )
|
||||||
{
|
{
|
||||||
|
|
||||||
case EVENT_SIGNAL:
|
case EVENT_SIGNAL:
|
||||||
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal ), signal_get_desc( e->param1.signal ));
|
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal ), signal_get_desc( e->param1.signal ));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_VARIABLE:
|
case EVENT_VARIABLE:
|
||||||
result = format_string(_(L"handler for variable '%ls'"), e->str_param1.c_str() );
|
result = format_string(_(L"handler for variable '%ls'"), e->str_param1.c_str() );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXIT:
|
case EVENT_EXIT:
|
||||||
if( e->param1.pid > 0 )
|
if( e->param1.pid > 0 )
|
||||||
{
|
{
|
||||||
result = format_string(_(L"exit handler for process %d"), e->param1.pid );
|
result = format_string(_(L"exit handler for process %d"), e->param1.pid );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
job_t *j = job_get_from_pid( -e->param1.pid );
|
job_t *j = job_get_from_pid( -e->param1.pid );
|
||||||
if( j )
|
if( j )
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
||||||
else
|
else
|
||||||
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid );
|
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_JOB_ID:
|
case EVENT_JOB_ID:
|
||||||
{
|
{
|
||||||
job_t *j = job_get( e->param1.job_id );
|
job_t *j = job_get( e->param1.job_id );
|
||||||
if( j )
|
if( j )
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
||||||
else
|
else
|
||||||
result = format_string(_(L"exit handler for job with job id %d"), e->param1.job_id );
|
result = format_string(_(L"exit handler for job with job id %d"), e->param1.job_id );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EVENT_GENERIC:
|
case EVENT_GENERIC:
|
||||||
result = format_string(_(L"handler for generic event '%ls'"), e->str_param1.c_str() );
|
result = format_string(_(L"handler for generic event '%ls'"), e->str_param1.c_str() );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = format_string(_(L"Unknown event type") );
|
result = format_string(_(L"Unknown event type") );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -237,16 +237,16 @@ static void show_all_handlers(void) {
|
||||||
|
|
||||||
void event_add_handler( const event_t *event )
|
void event_add_handler( const event_t *event )
|
||||||
{
|
{
|
||||||
event_t *e;
|
event_t *e;
|
||||||
|
|
||||||
CHECK( event, );
|
CHECK( event, );
|
||||||
|
|
||||||
e = event_copy( event, 0 );
|
e = event_copy( event, 0 );
|
||||||
|
|
||||||
if( e->type == EVENT_SIGNAL )
|
if( e->type == EVENT_SIGNAL )
|
||||||
{
|
{
|
||||||
signal_handle( e->param1.signal, 1 );
|
signal_handle( e->param1.signal, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block around updating the events vector
|
// Block around updating the events vector
|
||||||
signal_block();
|
signal_block();
|
||||||
|
@ -257,75 +257,75 @@ void event_add_handler( const event_t *event )
|
||||||
void event_remove( event_t *criterion )
|
void event_remove( event_t *criterion )
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
event_list_t new_list;
|
event_list_t new_list;
|
||||||
|
|
||||||
CHECK( criterion, );
|
CHECK( criterion, );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Because of concurrency issues (env_remove could remove an event
|
Because of concurrency issues (env_remove could remove an event
|
||||||
that is currently being executed), env_remove does not actually
|
that is currently being executed), env_remove does not actually
|
||||||
free any events - instead it simply moves all events that should
|
free any events - instead it simply moves all events that should
|
||||||
be removed from the event list to the killme list, and the ones
|
be removed from the event list to the killme list, and the ones
|
||||||
that shouldn't be killed to new_list, and then drops the empty
|
that shouldn't be killed to new_list, and then drops the empty
|
||||||
events-list.
|
events-list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( events.empty() )
|
if( events.empty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for( i=0; i<events.size(); i++ )
|
for( i=0; i<events.size(); i++ )
|
||||||
{
|
{
|
||||||
event_t *n = events.at(i);
|
event_t *n = events.at(i);
|
||||||
if( event_match( criterion, n ) )
|
if( event_match( criterion, n ) )
|
||||||
{
|
{
|
||||||
killme.push_back(n);
|
killme.push_back(n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If this event was a signal handler and no other handler handles
|
If this event was a signal handler and no other handler handles
|
||||||
the specified signal type, do not handle that type of signal any
|
the specified signal type, do not handle that type of signal any
|
||||||
more.
|
more.
|
||||||
*/
|
*/
|
||||||
if( n->type == EVENT_SIGNAL )
|
if( n->type == EVENT_SIGNAL )
|
||||||
{
|
{
|
||||||
event_t e = event_t::signal_event(n->param1.signal);
|
event_t e = event_t::signal_event(n->param1.signal);
|
||||||
if( event_get( &e, 0 ) == 1 )
|
if( event_get( &e, 0 ) == 1 )
|
||||||
{
|
{
|
||||||
signal_handle( e.param1.signal, 0 );
|
signal_handle( e.param1.signal, 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_list.push_back(n);
|
new_list.push_back(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal_block();
|
signal_block();
|
||||||
events.swap(new_list);
|
events.swap(new_list);
|
||||||
signal_unblock();
|
signal_unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int event_get( event_t *criterion, std::vector<event_t *> *out )
|
int event_get( event_t *criterion, std::vector<event_t *> *out )
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
if( events.empty() )
|
if( events.empty() )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
CHECK( criterion, 0 );
|
CHECK( criterion, 0 );
|
||||||
|
|
||||||
for( i=0; i<events.size(); i++ )
|
for( i=0; i<events.size(); i++ )
|
||||||
{
|
{
|
||||||
event_t *n = events.at(i);
|
event_t *n = events.at(i);
|
||||||
if( event_match(criterion, n ) )
|
if( event_match(criterion, n ) )
|
||||||
{
|
{
|
||||||
found++;
|
found++;
|
||||||
if( out )
|
if( out )
|
||||||
out->push_back(n);
|
out->push_back(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool event_is_signal_observed(int sig)
|
bool event_is_signal_observed(int sig)
|
||||||
|
@ -376,62 +376,62 @@ static int event_is_killed( event_t *e )
|
||||||
static void event_fire_internal( const event_t *event )
|
static void event_fire_internal( const event_t *event )
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
event_list_t fire;
|
event_list_t fire;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
First we free all events that have been removed
|
First we free all events that have been removed
|
||||||
*/
|
*/
|
||||||
event_free_kills();
|
event_free_kills();
|
||||||
|
|
||||||
if( events.empty() )
|
if( events.empty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Then we iterate over all events, adding events that should be
|
Then we iterate over all events, adding events that should be
|
||||||
fired to a second list. We need to do this in a separate step
|
fired to a second list. We need to do this in a separate step
|
||||||
since an event handler might call event_remove or
|
since an event handler might call event_remove or
|
||||||
event_add_handler, which will change the contents of the \c
|
event_add_handler, which will change the contents of the \c
|
||||||
events list.
|
events list.
|
||||||
*/
|
*/
|
||||||
for( i=0; i<events.size(); i++ )
|
for( i=0; i<events.size(); i++ )
|
||||||
{
|
{
|
||||||
event_t *criterion = events.at(i);
|
event_t *criterion = events.at(i);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if this event is a match
|
Check if this event is a match
|
||||||
*/
|
*/
|
||||||
if(event_match( criterion, event ) )
|
if(event_match( criterion, event ) )
|
||||||
{
|
{
|
||||||
fire.push_back(criterion);
|
fire.push_back(criterion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No matches. Time to return.
|
No matches. Time to return.
|
||||||
*/
|
*/
|
||||||
if( fire.empty() )
|
if( fire.empty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Iterate over our list of matching events
|
Iterate over our list of matching events
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for( i=0; i<fire.size(); i++ )
|
for( i=0; i<fire.size(); i++ )
|
||||||
{
|
{
|
||||||
event_t *criterion = fire.at(i);
|
event_t *criterion = fire.at(i);
|
||||||
int prev_status;
|
int prev_status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if this event has been removed, if so, dont fire it
|
Check if this event has been removed, if so, dont fire it
|
||||||
*/
|
*/
|
||||||
if( event_is_killed( criterion ) )
|
if( event_is_killed( criterion ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fire event
|
Fire event
|
||||||
*/
|
*/
|
||||||
wcstring buffer = criterion->function_name;
|
wcstring buffer = criterion->function_name;
|
||||||
|
|
||||||
if (event->arguments.get())
|
if (event->arguments.get())
|
||||||
{
|
{
|
||||||
|
@ -443,28 +443,28 @@ static void event_fire_internal( const event_t *event )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
|
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Event handlers are not part of the main flow of code, so
|
Event handlers are not part of the main flow of code, so
|
||||||
they are marked as non-interactive
|
they are marked as non-interactive
|
||||||
*/
|
*/
|
||||||
proc_push_interactive(0);
|
proc_push_interactive(0);
|
||||||
prev_status = proc_get_last_status();
|
prev_status = proc_get_last_status();
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
|
|
||||||
block_t *block = new event_block_t(event);
|
block_t *block = new event_block_t(event);
|
||||||
parser.push_block(block);
|
parser.push_block(block);
|
||||||
parser.eval( buffer, io_chain_t(), TOP );
|
parser.eval( buffer, io_chain_t(), TOP );
|
||||||
parser.pop_block();
|
parser.pop_block();
|
||||||
proc_pop_interactive();
|
proc_pop_interactive();
|
||||||
proc_set_last_status( prev_status );
|
proc_set_last_status( prev_status );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Free killed events
|
Free killed events
|
||||||
*/
|
*/
|
||||||
event_free_kills();
|
event_free_kills();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,78 +474,78 @@ static void event_fire_internal( const event_t *event )
|
||||||
static void event_fire_delayed()
|
static void event_fire_delayed()
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If is_event is one, we are running the event-handler non-recursively.
|
If is_event is one, we are running the event-handler non-recursively.
|
||||||
|
|
||||||
When the event handler has called a piece of code that triggers
|
When the event handler has called a piece of code that triggers
|
||||||
another event, we do not want to fire delayed events because of
|
another event, we do not want to fire delayed events because of
|
||||||
concurrency problems.
|
concurrency problems.
|
||||||
*/
|
*/
|
||||||
if( ! blocked.empty() && is_event==1)
|
if( ! blocked.empty() && is_event==1)
|
||||||
{
|
{
|
||||||
event_list_t new_blocked;
|
event_list_t new_blocked;
|
||||||
|
|
||||||
for( i=0; i<blocked.size(); i++ )
|
for( i=0; i<blocked.size(); i++ )
|
||||||
{
|
{
|
||||||
event_t *e = blocked.at(i);
|
event_t *e = blocked.at(i);
|
||||||
if( event_is_blocked( e ) )
|
if( event_is_blocked( e ) )
|
||||||
{
|
{
|
||||||
new_blocked.push_back(e);
|
new_blocked.push_back(e);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_fire_internal( e );
|
event_fire_internal( e );
|
||||||
event_free( e );
|
event_free( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blocked.swap(new_blocked);
|
blocked.swap(new_blocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
while( sig_list[active_list].count > 0 )
|
while( sig_list[active_list].count > 0 )
|
||||||
{
|
{
|
||||||
signal_list_t *lst;
|
signal_list_t *lst;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Switch signal lists
|
Switch signal lists
|
||||||
*/
|
*/
|
||||||
sig_list[1-active_list].count=0;
|
sig_list[1-active_list].count=0;
|
||||||
sig_list[1-active_list].overflow=0;
|
sig_list[1-active_list].overflow=0;
|
||||||
active_list=1-active_list;
|
active_list=1-active_list;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set up
|
Set up
|
||||||
*/
|
*/
|
||||||
event_t e = event_t::signal_event(0);
|
event_t e = event_t::signal_event(0);
|
||||||
e.arguments.reset(new wcstring_list_t(1)); //one element
|
e.arguments.reset(new wcstring_list_t(1)); //one element
|
||||||
lst = &sig_list[1-active_list];
|
lst = &sig_list[1-active_list];
|
||||||
|
|
||||||
if( lst->overflow )
|
if( lst->overflow )
|
||||||
{
|
{
|
||||||
debug( 0, _( L"Signal list overflow. Signals have been ignored." ) );
|
debug( 0, _( L"Signal list overflow. Signals have been ignored." ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send all signals in our private list
|
Send all signals in our private list
|
||||||
*/
|
*/
|
||||||
for( int i=0; i < lst->count; i++ )
|
for( int i=0; i < lst->count; i++ )
|
||||||
{
|
{
|
||||||
e.param1.signal = lst->signal[i];
|
e.param1.signal = lst->signal[i];
|
||||||
e.arguments->at(0) = sig2wcs( e.param1.signal );
|
e.arguments->at(0) = sig2wcs( e.param1.signal );
|
||||||
if( event_is_blocked( &e ) )
|
if( event_is_blocked( &e ) )
|
||||||
{
|
{
|
||||||
blocked.push_back(event_copy(&e, 1));
|
blocked.push_back(event_copy(&e, 1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_fire_internal( &e );
|
event_fire_internal( &e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.arguments.reset(NULL);
|
e.arguments.reset(NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_fire_signal(int signal)
|
void event_fire_signal(int signal)
|
||||||
|
@ -566,32 +566,32 @@ void event_fire_signal(int signal)
|
||||||
void event_fire( event_t *event )
|
void event_fire( event_t *event )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( event && (event->type == EVENT_SIGNAL) )
|
if( event && (event->type == EVENT_SIGNAL) )
|
||||||
{
|
{
|
||||||
event_fire_signal(event->param1.signal);
|
event_fire_signal(event->param1.signal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_event++;
|
is_event++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fire events triggered by signals
|
Fire events triggered by signals
|
||||||
*/
|
*/
|
||||||
event_fire_delayed();
|
event_fire_delayed();
|
||||||
|
|
||||||
if( event )
|
if( event )
|
||||||
{
|
{
|
||||||
if( event_is_blocked( event ) )
|
if( event_is_blocked( event ) )
|
||||||
{
|
{
|
||||||
blocked.push_back(event_copy(event, 1));
|
blocked.push_back(event_copy(event, 1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_fire_internal( event );
|
event_fire_internal( event );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_event--;
|
is_event--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -611,29 +611,29 @@ void event_destroy()
|
||||||
|
|
||||||
void event_free( event_t *e )
|
void event_free( event_t *e )
|
||||||
{
|
{
|
||||||
CHECK( e, );
|
CHECK( e, );
|
||||||
delete e;
|
delete e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void event_fire_generic_internal(const wchar_t *name, ...)
|
void event_fire_generic_internal(const wchar_t *name, ...)
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
wchar_t *arg;
|
wchar_t *arg;
|
||||||
|
|
||||||
CHECK( name, );
|
CHECK( name, );
|
||||||
|
|
||||||
event_t ev(EVENT_GENERIC);
|
event_t ev(EVENT_GENERIC);
|
||||||
ev.str_param1 = name;
|
ev.str_param1 = name;
|
||||||
ev.arguments.reset(new wcstring_list_t);
|
ev.arguments.reset(new wcstring_list_t);
|
||||||
va_start( va, name );
|
va_start( va, name );
|
||||||
while( (arg=va_arg(va, wchar_t *) )!= 0 )
|
while( (arg=va_arg(va, wchar_t *) )!= 0 )
|
||||||
{
|
{
|
||||||
ev.arguments->push_back(arg);
|
ev.arguments->push_back(arg);
|
||||||
}
|
}
|
||||||
va_end( va );
|
va_end( va );
|
||||||
|
|
||||||
event_fire( &ev );
|
event_fire( &ev );
|
||||||
ev.arguments.reset(NULL);
|
ev.arguments.reset(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
event.h
54
event.h
|
@ -1,11 +1,11 @@
|
||||||
/** \file event.h
|
/** \file event.h
|
||||||
|
|
||||||
Functions for handling event triggers
|
Functions for handling event triggers
|
||||||
|
|
||||||
Because most of these functions can be called by signal
|
Because most of these functions can be called by signal
|
||||||
handler, it is important to make it well defined when these
|
handler, it is important to make it well defined when these
|
||||||
functions produce output or perform memory allocations, since
|
functions produce output or perform memory allocations, since
|
||||||
such functions may not be safely called by signal handlers.
|
such functions may not be safely called by signal handlers.
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -31,14 +31,14 @@
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
EVENT_ANY, /**< Matches any event type (Not always any event, as the function name may limit the choice as well */
|
EVENT_ANY, /**< Matches any event type (Not always any event, as the function name may limit the choice as well */
|
||||||
EVENT_SIGNAL, /**< An event triggered by a signal */
|
EVENT_SIGNAL, /**< An event triggered by a signal */
|
||||||
EVENT_VARIABLE, /**< An event triggered by a variable update */
|
EVENT_VARIABLE, /**< An event triggered by a variable update */
|
||||||
EVENT_EXIT, /**< An event triggered by a job or process exit */
|
EVENT_EXIT, /**< An event triggered by a job or process exit */
|
||||||
EVENT_JOB_ID, /**< An event triggered by a job exit */
|
EVENT_JOB_ID, /**< An event triggered by a job exit */
|
||||||
EVENT_GENERIC, /**< A generic event */
|
EVENT_GENERIC, /**< A generic event */
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The structure which represents an event. The event_t struct has
|
The structure which represents an event. The event_t struct has
|
||||||
|
@ -49,14 +49,14 @@ enum
|
||||||
*/
|
*/
|
||||||
struct event_t
|
struct event_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Type of event
|
Type of event
|
||||||
*/
|
*/
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
/** The type-specific parameter. The int types are one of the following:
|
/** The type-specific parameter. The int types are one of the following:
|
||||||
|
|
||||||
signal: Signal number for signal-type events.Use EVENT_ANY_SIGNAL to match any signal
|
signal: Signal number for signal-type events.Use EVENT_ANY_SIGNAL to match any signal
|
||||||
pid: Process id for process-type events. Use EVENT_ANY_PID to match any pid.
|
pid: Process id for process-type events. Use EVENT_ANY_PID to match any pid.
|
||||||
job_id: Job id for EVENT_JOB_ID type events
|
job_id: Job id for EVENT_JOB_ID type events
|
||||||
*/
|
*/
|
||||||
|
@ -73,16 +73,16 @@ struct event_t
|
||||||
*/
|
*/
|
||||||
wcstring str_param1;
|
wcstring str_param1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The name of the event handler function
|
The name of the event handler function
|
||||||
*/
|
*/
|
||||||
wcstring function_name;
|
wcstring function_name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The argument list. Only used when sending a new event using
|
The argument list. Only used when sending a new event using
|
||||||
event_fire. In all other situations, the value of this variable
|
event_fire. In all other situations, the value of this variable
|
||||||
is ignored.
|
is ignored.
|
||||||
*/
|
*/
|
||||||
std::auto_ptr<wcstring_list_t> arguments;
|
std::auto_ptr<wcstring_list_t> arguments;
|
||||||
|
|
||||||
event_t(int t) : type(t), param1(), str_param1(), function_name(), arguments() { }
|
event_t(int t) : type(t), param1(), str_param1(), function_name(), arguments() { }
|
||||||
|
|
2
exec.h
2
exec.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file exec.h
|
/** \file exec.h
|
||||||
Prototypes for functions for executing a program
|
Prototypes for functions for executing a program
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_EXEC_H
|
#ifndef FISH_EXEC_H
|
||||||
|
|
1212
expand.cpp
1212
expand.cpp
File diff suppressed because it is too large
Load diff
54
expand.h
54
expand.h
|
@ -69,33 +69,33 @@ class completion_t;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/** Character represeting a home directory */
|
/** Character represeting a home directory */
|
||||||
HOME_DIRECTORY = EXPAND_RESERVED,
|
HOME_DIRECTORY = EXPAND_RESERVED,
|
||||||
|
|
||||||
/** Character represeting process expansion */
|
/** Character represeting process expansion */
|
||||||
PROCESS_EXPAND,
|
PROCESS_EXPAND,
|
||||||
|
|
||||||
/** Character representing variable expansion */
|
/** Character representing variable expansion */
|
||||||
VARIABLE_EXPAND,
|
VARIABLE_EXPAND,
|
||||||
|
|
||||||
/** Character rpresenting variable expansion into a single element*/
|
/** Character rpresenting variable expansion into a single element*/
|
||||||
VARIABLE_EXPAND_SINGLE,
|
VARIABLE_EXPAND_SINGLE,
|
||||||
|
|
||||||
/** Character representing the start of a bracket expansion */
|
/** Character representing the start of a bracket expansion */
|
||||||
BRACKET_BEGIN,
|
BRACKET_BEGIN,
|
||||||
|
|
||||||
/** Character representing the end of a bracket expansion */
|
/** Character representing the end of a bracket expansion */
|
||||||
BRACKET_END,
|
BRACKET_END,
|
||||||
|
|
||||||
/** Character representing separation between two bracket elements */
|
/** Character representing separation between two bracket elements */
|
||||||
BRACKET_SEP,
|
BRACKET_SEP,
|
||||||
/**
|
/**
|
||||||
Separate subtokens in a token with this character.
|
Separate subtokens in a token with this character.
|
||||||
*/
|
*/
|
||||||
INTERNAL_SEPARATOR,
|
INTERNAL_SEPARATOR,
|
||||||
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,14 +103,14 @@ enum
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/** Error */
|
/** Error */
|
||||||
EXPAND_ERROR,
|
EXPAND_ERROR,
|
||||||
/** Ok */
|
/** Ok */
|
||||||
EXPAND_OK,
|
EXPAND_OK,
|
||||||
/** Ok, a wildcard in the string matched no files */
|
/** Ok, a wildcard in the string matched no files */
|
||||||
EXPAND_WILDCARD_NO_MATCH,
|
EXPAND_WILDCARD_NO_MATCH,
|
||||||
/* Ok, a wildcard in the string matched a file */
|
/* Ok, a wildcard in the string matched a file */
|
||||||
EXPAND_WILDCARD_MATCH
|
EXPAND_WILDCARD_MATCH
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
|
/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
|
||||||
|
|
1332
fallback.cpp
1332
fallback.cpp
File diff suppressed because it is too large
Load diff
78
fallback.h
78
fallback.h
|
@ -63,14 +63,14 @@ typedef char tputs_arg_t;
|
||||||
*/
|
*/
|
||||||
struct winsize
|
struct winsize
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Number of rows
|
Number of rows
|
||||||
*/
|
*/
|
||||||
unsigned short ws_row;
|
unsigned short ws_row;
|
||||||
/**
|
/**
|
||||||
Number of columns
|
Number of columns
|
||||||
*/
|
*/
|
||||||
unsigned short ws_col;
|
unsigned short ws_col;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -312,8 +312,8 @@ long convert_digit( wchar_t d, int base );
|
||||||
supported.
|
supported.
|
||||||
*/
|
*/
|
||||||
long wcstol(const wchar_t *nptr,
|
long wcstol(const wchar_t *nptr,
|
||||||
wchar_t **endptr,
|
wchar_t **endptr,
|
||||||
int base);
|
int base);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_WCSLCAT
|
#ifndef HAVE_WCSLCAT
|
||||||
|
@ -361,10 +361,10 @@ size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
|
||||||
*/
|
*/
|
||||||
struct drand48_data
|
struct drand48_data
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Seed value
|
Seed value
|
||||||
*/
|
*/
|
||||||
unsigned int seed;
|
unsigned int seed;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -411,8 +411,8 @@ char * textdomain( const char * domainname );
|
||||||
Fallback implementation of dcgettext. Just returns the original string.
|
Fallback implementation of dcgettext. Just returns the original string.
|
||||||
*/
|
*/
|
||||||
char * dcgettext ( const char * domainname,
|
char * dcgettext ( const char * domainname,
|
||||||
const char * msgid,
|
const char * msgid,
|
||||||
int category );
|
int category );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -443,42 +443,42 @@ int killpg( int pgr, int sig );
|
||||||
*/
|
*/
|
||||||
struct option
|
struct option
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Name of option
|
Name of option
|
||||||
*/
|
*/
|
||||||
const char *name;
|
const char *name;
|
||||||
/**
|
/**
|
||||||
Flag
|
Flag
|
||||||
*/
|
*/
|
||||||
int has_arg;
|
int has_arg;
|
||||||
/**
|
/**
|
||||||
Flag
|
Flag
|
||||||
*/
|
*/
|
||||||
int *flag;
|
int *flag;
|
||||||
/**
|
/**
|
||||||
Return value
|
Return value
|
||||||
*/
|
*/
|
||||||
int val;
|
int val;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
#ifndef no_argument
|
#ifndef no_argument
|
||||||
#define no_argument 0
|
#define no_argument 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef required_argument
|
#ifndef required_argument
|
||||||
#define required_argument 1
|
#define required_argument 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef optional_argument
|
#ifndef optional_argument
|
||||||
#define optional_argument 2
|
#define optional_argument 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int getopt_long(int argc,
|
int getopt_long(int argc,
|
||||||
char * const argv[],
|
char * const argv[],
|
||||||
const char *optstring,
|
const char *optstring,
|
||||||
const struct option *longopts,
|
const struct option *longopts,
|
||||||
int *longindex);
|
int *longindex);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
524
fish.cpp
524
fish.cpp
|
@ -17,7 +17,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
||||||
/** \file fish.c
|
/** \file fish.c
|
||||||
The main loop of <tt>fish</tt>.
|
The main loop of <tt>fish</tt>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -217,27 +217,27 @@ static int read_init(const struct config_paths_t &paths)
|
||||||
{
|
{
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
const io_chain_t empty_ios;
|
const io_chain_t empty_ios;
|
||||||
parser.eval( L"builtin . " + paths.data + L"/config.fish 2>/dev/null", empty_ios, TOP );
|
parser.eval( L"builtin . " + paths.data + L"/config.fish 2>/dev/null", empty_ios, TOP );
|
||||||
parser.eval( L"builtin . " + paths.sysconf + L"/config.fish 2>/dev/null", empty_ios, TOP );
|
parser.eval( L"builtin . " + paths.sysconf + L"/config.fish 2>/dev/null", empty_ios, TOP );
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We need to get the configuration directory before we can source the user configuration file
|
We need to get the configuration directory before we can source the user configuration file
|
||||||
*/
|
*/
|
||||||
wcstring config_dir;
|
wcstring config_dir;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If path_get_config returns false then we have no configuration directory
|
If path_get_config returns false then we have no configuration directory
|
||||||
and no custom config to load.
|
and no custom config to load.
|
||||||
*/
|
*/
|
||||||
if (path_get_config(config_dir))
|
if (path_get_config(config_dir))
|
||||||
{
|
{
|
||||||
wcstring config_dir_escaped = escape_string( config_dir, 1 );
|
wcstring config_dir_escaped = escape_string( config_dir, 1 );
|
||||||
wcstring eval_buff = format_string(L"builtin . %ls/config.fish 2>/dev/null", config_dir_escaped.c_str());
|
wcstring eval_buff = format_string(L"builtin . %ls/config.fish 2>/dev/null", config_dir_escaped.c_str());
|
||||||
parser.eval( eval_buff, empty_ios, TOP );
|
parser.eval( eval_buff, empty_ios, TOP );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -247,162 +247,162 @@ static int read_init(const struct config_paths_t &paths)
|
||||||
*/
|
*/
|
||||||
static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
|
static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
|
||||||
{
|
{
|
||||||
int my_optind;
|
int my_optind;
|
||||||
int force_interactive=0;
|
int force_interactive=0;
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
static struct option
|
static struct option
|
||||||
long_options[] =
|
long_options[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"command", required_argument, 0, 'c'
|
"command", required_argument, 0, 'c'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"debug-level", required_argument, 0, 'd'
|
"debug-level", required_argument, 0, 'd'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"interactive", no_argument, 0, 'i'
|
"interactive", no_argument, 0, 'i'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"login", no_argument, 0, 'l'
|
"login", no_argument, 0, 'l'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"no-execute", no_argument, 0, 'n'
|
"no-execute", no_argument, 0, 'n'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"profile", required_argument, 0, 'p'
|
"profile", required_argument, 0, 'p'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"help", no_argument, 0, 'h'
|
"help", no_argument, 0, 'h'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"version", no_argument, 0, 'v'
|
"version", no_argument, 0, 'v'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int opt = getopt_long( argc,
|
int opt = getopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
GETOPT_STRING,
|
GETOPT_STRING,
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
|
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
{
|
{
|
||||||
*cmd_ptr = optarg;
|
*cmd_ptr = optarg;
|
||||||
is_interactive_session = 0;
|
is_interactive_session = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
long tmp;
|
long tmp;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
tmp = strtol(optarg, &end, 10);
|
tmp = strtol(optarg, &end, 10);
|
||||||
|
|
||||||
if( tmp >= 0 && tmp <=10 && !*end && !errno )
|
if( tmp >= 0 && tmp <=10 && !*end && !errno )
|
||||||
{
|
{
|
||||||
debug_level = (int)tmp;
|
debug_level = (int)tmp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug( 0, _(L"Invalid value '%s' for debug level switch"), optarg );
|
debug( 0, _(L"Invalid value '%s' for debug level switch"), optarg );
|
||||||
exit_without_destructors(1);
|
exit_without_destructors(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
{
|
{
|
||||||
*cmd_ptr = "__fish_print_help fish";
|
*cmd_ptr = "__fish_print_help fish";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
force_interactive = 1;
|
force_interactive = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
{
|
||||||
is_login=1;
|
is_login=1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
{
|
{
|
||||||
no_exec=1;
|
no_exec=1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
{
|
{
|
||||||
profile = optarg;
|
profile = optarg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
{
|
{
|
||||||
fwprintf( stderr,
|
fwprintf( stderr,
|
||||||
_(L"%s, version %s\n"),
|
_(L"%s, version %s\n"),
|
||||||
PACKAGE_NAME,
|
PACKAGE_NAME,
|
||||||
PACKAGE_VERSION );
|
PACKAGE_VERSION );
|
||||||
exit_without_destructors( 0 );
|
exit_without_destructors( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
{
|
{
|
||||||
exit_without_destructors( 1 );
|
exit_without_destructors( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my_optind = optind;
|
my_optind = optind;
|
||||||
|
|
||||||
is_login |= (strcmp( argv[0], "-fish") == 0);
|
is_login |= (strcmp( argv[0], "-fish") == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We are an interactive session if we have not been given an
|
We are an interactive session if we have not been given an
|
||||||
explicit command to execute, _and_ stdin is a tty.
|
explicit command to execute, _and_ stdin is a tty.
|
||||||
*/
|
*/
|
||||||
is_interactive_session &= (*cmd_ptr == 0);
|
is_interactive_session &= (*cmd_ptr == 0);
|
||||||
is_interactive_session &= (my_optind == argc);
|
is_interactive_session &= (my_optind == argc);
|
||||||
is_interactive_session &= isatty(STDIN_FILENO);
|
is_interactive_session &= isatty(STDIN_FILENO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We are also an interactive session if we have are forced-
|
We are also an interactive session if we have are forced-
|
||||||
*/
|
*/
|
||||||
is_interactive_session |= force_interactive;
|
is_interactive_session |= force_interactive;
|
||||||
|
|
||||||
return my_optind;
|
return my_optind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -412,68 +412,68 @@ static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
|
||||||
|
|
||||||
static wcstring full_escape( const wchar_t *in )
|
static wcstring full_escape( const wchar_t *in )
|
||||||
{
|
{
|
||||||
wcstring out;
|
wcstring out;
|
||||||
for( ; *in; in++ )
|
for( ; *in; in++ )
|
||||||
{
|
{
|
||||||
if( *in < 32 )
|
if( *in < 32 )
|
||||||
{
|
{
|
||||||
append_format( out, L"\\x%.2x", *in );
|
append_format( out, L"\\x%.2x", *in );
|
||||||
}
|
}
|
||||||
else if( *in < 128 )
|
else if( *in < 128 )
|
||||||
{
|
{
|
||||||
out.push_back(*in);
|
out.push_back(*in);
|
||||||
}
|
}
|
||||||
else if( *in < 65536 )
|
else if( *in < 65536 )
|
||||||
{
|
{
|
||||||
append_format( out, L"\\u%.4x", *in );
|
append_format( out, L"\\u%.4x", *in );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
append_format( out, L"\\U%.8x", *in );
|
append_format( out, L"\\U%.8x", *in );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int g_fork_count;
|
extern int g_fork_count;
|
||||||
int main( int argc, char **argv )
|
int main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
int res=1;
|
int res=1;
|
||||||
const char *cmd=0;
|
const char *cmd=0;
|
||||||
int my_optind=0;
|
int my_optind=0;
|
||||||
|
|
||||||
set_main_thread();
|
set_main_thread();
|
||||||
setup_fork_guards();
|
setup_fork_guards();
|
||||||
|
|
||||||
wsetlocale( LC_ALL, L"" );
|
wsetlocale( LC_ALL, L"" );
|
||||||
is_interactive_session=1;
|
is_interactive_session=1;
|
||||||
program_name=L"fish";
|
program_name=L"fish";
|
||||||
|
|
||||||
//struct stat tmp;
|
//struct stat tmp;
|
||||||
//stat("----------FISH_HIT_MAIN----------", &tmp);
|
//stat("----------FISH_HIT_MAIN----------", &tmp);
|
||||||
|
|
||||||
my_optind = fish_parse_opt( argc, argv, &cmd );
|
my_optind = fish_parse_opt( argc, argv, &cmd );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No-exec is prohibited when in interactive mode
|
No-exec is prohibited when in interactive mode
|
||||||
*/
|
*/
|
||||||
if( is_interactive_session && no_exec)
|
if( is_interactive_session && no_exec)
|
||||||
{
|
{
|
||||||
debug( 1, _(L"Can not use the no-execute mode when running an interactive session") );
|
debug( 1, _(L"Can not use the no-execute mode when running an interactive session") );
|
||||||
no_exec = 0;
|
no_exec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
|
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
|
||||||
|
|
||||||
proc_init();
|
proc_init();
|
||||||
event_init();
|
event_init();
|
||||||
wutil_init();
|
wutil_init();
|
||||||
//parser_init();
|
//parser_init();
|
||||||
builtin_init();
|
builtin_init();
|
||||||
function_init();
|
function_init();
|
||||||
env_init(&paths);
|
env_init(&paths);
|
||||||
reader_init();
|
reader_init();
|
||||||
history_init();
|
history_init();
|
||||||
|
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
|
|
||||||
|
@ -481,91 +481,91 @@ int main( int argc, char **argv )
|
||||||
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
|
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
|
||||||
|
|
||||||
const io_chain_t empty_ios;
|
const io_chain_t empty_ios;
|
||||||
if( read_init(paths) )
|
if( read_init(paths) )
|
||||||
{
|
{
|
||||||
if( cmd != 0 )
|
if( cmd != 0 )
|
||||||
{
|
{
|
||||||
wchar_t *cmd_wcs = str2wcs( cmd );
|
wchar_t *cmd_wcs = str2wcs( cmd );
|
||||||
res = parser.eval( cmd_wcs, empty_ios, TOP );
|
res = parser.eval( cmd_wcs, empty_ios, TOP );
|
||||||
free(cmd_wcs);
|
free(cmd_wcs);
|
||||||
reader_exit(0, 0);
|
reader_exit(0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( my_optind == argc )
|
if( my_optind == argc )
|
||||||
{
|
{
|
||||||
res = reader_read( STDIN_FILENO, empty_ios );
|
res = reader_read( STDIN_FILENO, empty_ios );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char **ptr;
|
char **ptr;
|
||||||
char *file = *(argv+(my_optind++));
|
char *file = *(argv+(my_optind++));
|
||||||
int i;
|
int i;
|
||||||
int fd;
|
int fd;
|
||||||
wchar_t *rel_filename, *abs_filename;
|
wchar_t *rel_filename, *abs_filename;
|
||||||
|
|
||||||
|
|
||||||
if( ( fd = open(file, O_RDONLY) ) == -1 )
|
if( ( fd = open(file, O_RDONLY) ) == -1 )
|
||||||
{
|
{
|
||||||
wperror( L"open" );
|
wperror( L"open" );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK to not do this atomically since we cannot have gone multithreaded yet
|
// OK to not do this atomically since we cannot have gone multithreaded yet
|
||||||
set_cloexec(fd);
|
set_cloexec(fd);
|
||||||
|
|
||||||
if( *(argv+my_optind))
|
if( *(argv+my_optind))
|
||||||
{
|
{
|
||||||
wcstring sb;
|
wcstring sb;
|
||||||
for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ )
|
for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ )
|
||||||
{
|
{
|
||||||
if( i != 1 )
|
if( i != 1 )
|
||||||
sb.append( ARRAY_SEP_STR );
|
sb.append( ARRAY_SEP_STR );
|
||||||
sb.append( str2wcstring( *ptr ));
|
sb.append( str2wcstring( *ptr ));
|
||||||
}
|
}
|
||||||
|
|
||||||
env_set( L"argv", sb.c_str(), 0 );
|
env_set( L"argv", sb.c_str(), 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
rel_filename = str2wcs( file );
|
rel_filename = str2wcs( file );
|
||||||
abs_filename = wrealpath( rel_filename, 0 );
|
abs_filename = wrealpath( rel_filename, 0 );
|
||||||
|
|
||||||
if( !abs_filename )
|
if( !abs_filename )
|
||||||
{
|
{
|
||||||
abs_filename = wcsdup(rel_filename);
|
abs_filename = wcsdup(rel_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader_push_current_filename( intern( abs_filename ) );
|
reader_push_current_filename( intern( abs_filename ) );
|
||||||
free( rel_filename );
|
free( rel_filename );
|
||||||
free( abs_filename );
|
free( abs_filename );
|
||||||
|
|
||||||
res = reader_read( fd, empty_ios );
|
res = reader_read( fd, empty_ios );
|
||||||
|
|
||||||
if( res )
|
if( res )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug( 1,
|
||||||
_(L"Error while reading file %ls\n"),
|
_(L"Error while reading file %ls\n"),
|
||||||
reader_current_filename()?reader_current_filename(): _(L"Standard input") );
|
reader_current_filename()?reader_current_filename(): _(L"Standard input") );
|
||||||
}
|
}
|
||||||
reader_pop_current_filename();
|
reader_pop_current_filename();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
|
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
|
||||||
|
|
||||||
history_destroy();
|
history_destroy();
|
||||||
proc_destroy();
|
proc_destroy();
|
||||||
builtin_destroy();
|
builtin_destroy();
|
||||||
reader_destroy();
|
reader_destroy();
|
||||||
parser.destroy();
|
parser.destroy();
|
||||||
wutil_destroy();
|
wutil_destroy();
|
||||||
event_destroy();
|
event_destroy();
|
||||||
|
|
||||||
env_destroy();
|
env_destroy();
|
||||||
|
|
||||||
if (g_log_forks)
|
if (g_log_forks)
|
||||||
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
|
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
|
||||||
|
|
||||||
return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status();
|
return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status();
|
||||||
}
|
}
|
||||||
|
|
472
fish_indent.cpp
472
fish_indent.cpp
|
@ -17,7 +17,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
||||||
/** \file fish_indent.cpp
|
/** \file fish_indent.cpp
|
||||||
The fish_indent proegram.
|
The fish_indent proegram.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -51,22 +51,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
static void read_file( FILE *f, wcstring &b )
|
static void read_file( FILE *f, wcstring &b )
|
||||||
{
|
{
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
errno=0;
|
errno=0;
|
||||||
wint_t c = fgetwc( f );
|
wint_t c = fgetwc( f );
|
||||||
if( c == WEOF )
|
if( c == WEOF )
|
||||||
{
|
{
|
||||||
if( errno )
|
if( errno )
|
||||||
{
|
{
|
||||||
wperror(L"fgetwc");
|
wperror(L"fgetwc");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
b.push_back((wchar_t)c);
|
b.push_back((wchar_t)c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,175 +84,175 @@ static void insert_tabs( wcstring &out, int indent )
|
||||||
*/
|
*/
|
||||||
static int indent( wcstring &out, const wcstring &in, int flags )
|
static int indent( wcstring &out, const wcstring &in, int flags )
|
||||||
{
|
{
|
||||||
tokenizer tok;
|
tokenizer tok;
|
||||||
int res=0;
|
int res=0;
|
||||||
int is_command = 1;
|
int is_command = 1;
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
int do_indent = 1;
|
int do_indent = 1;
|
||||||
int prev_type = 0;
|
int prev_type = 0;
|
||||||
int prev_prev_type = 0;
|
int prev_prev_type = 0;
|
||||||
|
|
||||||
tok_init( &tok, in.c_str(), TOK_SHOW_COMMENTS );
|
tok_init( &tok, in.c_str(), TOK_SHOW_COMMENTS );
|
||||||
|
|
||||||
for( ; tok_has_next( &tok ); tok_next( &tok ) )
|
for( ; tok_has_next( &tok ); tok_next( &tok ) )
|
||||||
{
|
{
|
||||||
int type = tok_last_type( &tok );
|
int type = tok_last_type( &tok );
|
||||||
wchar_t *last = tok_last( &tok );
|
wchar_t *last = tok_last( &tok );
|
||||||
|
|
||||||
switch( type )
|
switch( type )
|
||||||
{
|
{
|
||||||
case TOK_STRING:
|
case TOK_STRING:
|
||||||
{
|
{
|
||||||
if( is_command )
|
if( is_command )
|
||||||
{
|
{
|
||||||
int next_indent = indent;
|
int next_indent = indent;
|
||||||
is_command = 0;
|
is_command = 0;
|
||||||
|
|
||||||
wcstring unesc = last;
|
wcstring unesc = last;
|
||||||
unescape_string(unesc, UNESCAPE_SPECIAL);
|
unescape_string(unesc, UNESCAPE_SPECIAL);
|
||||||
|
|
||||||
if( parser_keywords_is_block(unesc))
|
if( parser_keywords_is_block(unesc))
|
||||||
{
|
{
|
||||||
next_indent++;
|
next_indent++;
|
||||||
}
|
}
|
||||||
else if (unesc == L"else")
|
else if (unesc == L"else")
|
||||||
{
|
{
|
||||||
indent--;
|
indent--;
|
||||||
}
|
}
|
||||||
/* case should have the same indent level as switch*/
|
/* case should have the same indent level as switch*/
|
||||||
else if (unesc == L"case")
|
else if (unesc == L"case")
|
||||||
{
|
{
|
||||||
indent--;
|
indent--;
|
||||||
}
|
}
|
||||||
else if (unesc == L"end")
|
else if (unesc == L"end")
|
||||||
{
|
{
|
||||||
indent--;
|
indent--;
|
||||||
next_indent--;
|
next_indent--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( do_indent && flags && prev_type != TOK_PIPE )
|
if( do_indent && flags && prev_type != TOK_PIPE )
|
||||||
{
|
{
|
||||||
insert_tabs( out, indent );
|
insert_tabs( out, indent );
|
||||||
}
|
}
|
||||||
|
|
||||||
append_format(out, L"%ls", last );
|
append_format(out, L"%ls", last );
|
||||||
|
|
||||||
indent = next_indent;
|
indent = next_indent;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( prev_type != TOK_REDIRECT_FD )
|
if ( prev_type != TOK_REDIRECT_FD )
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
out.append( last );
|
out.append( last );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_END:
|
case TOK_END:
|
||||||
{
|
{
|
||||||
if( prev_type != TOK_END || prev_prev_type != TOK_END )
|
if( prev_type != TOK_END || prev_prev_type != TOK_END )
|
||||||
out.append( L"\n" );
|
out.append( L"\n" );
|
||||||
do_indent = 1;
|
do_indent = 1;
|
||||||
is_command = 1;
|
is_command = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_PIPE:
|
case TOK_PIPE:
|
||||||
{
|
{
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
if ( last[0] == '2' && !last[1] ) {
|
if ( last[0] == '2' && !last[1] ) {
|
||||||
out.append( L"^" );
|
out.append( L"^" );
|
||||||
} else if ( last[0] != '1' || last[1] ) {
|
} else if ( last[0] != '1' || last[1] ) {
|
||||||
out.append( last);
|
out.append( last);
|
||||||
out.append( L">" );
|
out.append( L">" );
|
||||||
}
|
}
|
||||||
out.append( L" | " );
|
out.append( L" | " );
|
||||||
is_command = 1;
|
is_command = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_REDIRECT_OUT:
|
case TOK_REDIRECT_OUT:
|
||||||
{
|
{
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
if ( wcscmp( last, L"2" ) == 0 ) {
|
if ( wcscmp( last, L"2" ) == 0 ) {
|
||||||
out.append( L"^" );
|
out.append( L"^" );
|
||||||
} else {
|
} else {
|
||||||
if ( wcscmp( last, L"1" ) != 0 )
|
if ( wcscmp( last, L"1" ) != 0 )
|
||||||
out.append( last );
|
out.append( last );
|
||||||
out.append( L"> " );
|
out.append( L"> " );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_REDIRECT_APPEND:
|
case TOK_REDIRECT_APPEND:
|
||||||
{
|
{
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
if ( wcscmp( last, L"2" ) == 0 ) {
|
if ( wcscmp( last, L"2" ) == 0 ) {
|
||||||
out.append( L"^^" );
|
out.append( L"^^" );
|
||||||
} else {
|
} else {
|
||||||
if ( wcscmp( last, L"1" ) != 0 )
|
if ( wcscmp( last, L"1" ) != 0 )
|
||||||
out.append( last );
|
out.append( last );
|
||||||
out.append( L">> " );
|
out.append( L">> " );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_REDIRECT_IN:
|
case TOK_REDIRECT_IN:
|
||||||
{
|
{
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
if ( wcscmp( last, L"0" ) != 0 )
|
if ( wcscmp( last, L"0" ) != 0 )
|
||||||
out.append( last );
|
out.append( last );
|
||||||
out.append( L"< " );
|
out.append( L"< " );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_REDIRECT_FD:
|
case TOK_REDIRECT_FD:
|
||||||
{
|
{
|
||||||
out.append( L" " );
|
out.append( L" " );
|
||||||
if ( wcscmp( last, L"1" ) != 0 )
|
if ( wcscmp( last, L"1" ) != 0 )
|
||||||
out.append( last );
|
out.append( last );
|
||||||
out.append( L">& " );
|
out.append( L">& " );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_BACKGROUND:
|
case TOK_BACKGROUND:
|
||||||
{
|
{
|
||||||
out.append( L"&\n" );
|
out.append( L"&\n" );
|
||||||
do_indent = 1;
|
do_indent = 1;
|
||||||
is_command = 1;
|
is_command = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_COMMENT:
|
case TOK_COMMENT:
|
||||||
{
|
{
|
||||||
if( do_indent && flags)
|
if( do_indent && flags)
|
||||||
{
|
{
|
||||||
insert_tabs( out, indent );
|
insert_tabs( out, indent );
|
||||||
}
|
}
|
||||||
|
|
||||||
append_format( out, L"%ls", last );
|
append_format( out, L"%ls", last );
|
||||||
do_indent = 1;
|
do_indent = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
debug( 0, L"Unknown token '%ls'", last );
|
debug( 0, L"Unknown token '%ls'", last );
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_prev_type = prev_type;
|
prev_prev_type = prev_type;
|
||||||
prev_type = type;
|
prev_type = type;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tok_destroy( &tok );
|
tok_destroy( &tok );
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -279,105 +279,105 @@ static void trim( wcstring &str )
|
||||||
*/
|
*/
|
||||||
int main( int argc, char **argv )
|
int main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
int do_indent=1;
|
int do_indent=1;
|
||||||
set_main_thread();
|
set_main_thread();
|
||||||
setup_fork_guards();
|
setup_fork_guards();
|
||||||
|
|
||||||
wsetlocale( LC_ALL, L"" );
|
wsetlocale( LC_ALL, L"" );
|
||||||
program_name=L"fish_indent";
|
program_name=L"fish_indent";
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
static struct option
|
static struct option
|
||||||
long_options[] =
|
long_options[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"no-indent", no_argument, 0, 'i'
|
"no-indent", no_argument, 0, 'i'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"help", no_argument, 0, 'h'
|
"help", no_argument, 0, 'h'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"version", no_argument, 0, 'v'
|
"version", no_argument, 0, 'v'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int opt = getopt_long( argc,
|
int opt = getopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
GETOPT_STRING,
|
GETOPT_STRING,
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
|
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
{
|
{
|
||||||
print_help( "fish_indent", 1 );
|
print_help( "fish_indent", 1 );
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
{
|
{
|
||||||
fwprintf( stderr,
|
fwprintf( stderr,
|
||||||
_(L"%ls, version %s\n"),
|
_(L"%ls, version %s\n"),
|
||||||
program_name,
|
program_name,
|
||||||
PACKAGE_VERSION );
|
PACKAGE_VERSION );
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
do_indent = 0;
|
do_indent = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
{
|
{
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring sb_in, sb_out;
|
wcstring sb_in, sb_out;
|
||||||
read_file( stdin, sb_in );
|
read_file( stdin, sb_in );
|
||||||
|
|
||||||
wutil_init();
|
wutil_init();
|
||||||
|
|
||||||
if( !indent( sb_out, sb_in, do_indent ) )
|
if( !indent( sb_out, sb_in, do_indent ) )
|
||||||
{
|
{
|
||||||
trim(sb_out);
|
trim(sb_out);
|
||||||
fwprintf( stdout, L"%ls", sb_out.c_str() );
|
fwprintf( stdout, L"%ls", sb_out.c_str() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Indenting failed - print original input
|
Indenting failed - print original input
|
||||||
*/
|
*/
|
||||||
fwprintf( stdout, L"%ls", sb_in.c_str() );
|
fwprintf( stdout, L"%ls", sb_in.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wutil_destroy();
|
wutil_destroy();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
1826
fish_pager.cpp
1826
fish_pager.cpp
File diff suppressed because it is too large
Load diff
636
fish_tests.cpp
636
fish_tests.cpp
|
@ -1,5 +1,5 @@
|
||||||
/** \file fish_tests.c
|
/** \file fish_tests.c
|
||||||
Various bug and feature tests. Compiled and run by make test.
|
Various bug and feature tests. Compiled and run by make test.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -95,11 +95,11 @@ static int err_count=0;
|
||||||
*/
|
*/
|
||||||
static void say( const wchar_t *blah, ... )
|
static void say( const wchar_t *blah, ... )
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start( va, blah );
|
va_start( va, blah );
|
||||||
vwprintf( blah, va );
|
vwprintf( blah, va );
|
||||||
va_end( va );
|
va_end( va );
|
||||||
wprintf( L"\n" );
|
wprintf( L"\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,14 +107,14 @@ static void say( const wchar_t *blah, ... )
|
||||||
*/
|
*/
|
||||||
static void err( const wchar_t *blah, ... )
|
static void err( const wchar_t *blah, ... )
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start( va, blah );
|
va_start( va, blah );
|
||||||
err_count++;
|
err_count++;
|
||||||
|
|
||||||
wprintf( L"Error: " );
|
wprintf( L"Error: " );
|
||||||
vwprintf( blah, va );
|
vwprintf( blah, va );
|
||||||
va_end( va );
|
va_end( va );
|
||||||
wprintf( L"\n" );
|
wprintf( L"\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,40 +123,40 @@ static void err( const wchar_t *blah, ... )
|
||||||
*/
|
*/
|
||||||
static void test_escape()
|
static void test_escape()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
wcstring sb;
|
wcstring sb;
|
||||||
|
|
||||||
say( L"Testing escaping and unescaping" );
|
say( L"Testing escaping and unescaping" );
|
||||||
|
|
||||||
for( i=0; i<ESCAPE_TEST_COUNT; i++ )
|
for( i=0; i<ESCAPE_TEST_COUNT; i++ )
|
||||||
{
|
{
|
||||||
const wchar_t *o, *e, *u;
|
const wchar_t *o, *e, *u;
|
||||||
|
|
||||||
sb.clear();
|
sb.clear();
|
||||||
while( rand() % ESCAPE_TEST_LENGTH )
|
while( rand() % ESCAPE_TEST_LENGTH )
|
||||||
{
|
{
|
||||||
sb.push_back((rand() %ESCAPE_TEST_CHAR) +1 );
|
sb.push_back((rand() %ESCAPE_TEST_CHAR) +1 );
|
||||||
}
|
}
|
||||||
o = (const wchar_t *)sb.c_str();
|
o = (const wchar_t *)sb.c_str();
|
||||||
e = escape(o, 1);
|
e = escape(o, 1);
|
||||||
u = unescape( e, 0 );
|
u = unescape( e, 0 );
|
||||||
if( !o || !e || !u )
|
if( !o || !e || !u )
|
||||||
{
|
{
|
||||||
err( L"Escaping cycle of string %ls produced null pointer on %ls", o, e?L"unescaping":L"escaping" );
|
err( L"Escaping cycle of string %ls produced null pointer on %ls", o, e?L"unescaping":L"escaping" );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( wcscmp(o, u) )
|
if( wcscmp(o, u) )
|
||||||
{
|
{
|
||||||
err( L"Escaping cycle of string %ls produced different string %ls", o, u );
|
err( L"Escaping cycle of string %ls produced different string %ls", o, u );
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
free( (void *)e );
|
free( (void *)e );
|
||||||
free( (void *)u );
|
free( (void *)u );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_format(void) {
|
static void test_format(void) {
|
||||||
|
@ -198,81 +198,81 @@ static void test_format(void) {
|
||||||
*/
|
*/
|
||||||
static void test_convert()
|
static void test_convert()
|
||||||
{
|
{
|
||||||
/* char o[] =
|
/* char o[] =
|
||||||
{
|
{
|
||||||
-17, -128, -121, -68, 0
|
-17, -128, -121, -68, 0
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
wchar_t *w = str2wcs(o);
|
wchar_t *w = str2wcs(o);
|
||||||
char *n = wcs2str(w);
|
char *n = wcs2str(w);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i=0; o[i]; i++ )
|
for( i=0; o[i]; i++ )
|
||||||
{
|
{
|
||||||
bitprint(o[i]);;
|
bitprint(o[i]);;
|
||||||
//wprintf(L"%d ", o[i]);
|
//wprintf(L"%d ", o[i]);
|
||||||
}
|
}
|
||||||
wprintf(L"\n");
|
wprintf(L"\n");
|
||||||
|
|
||||||
for( i=0; w[i]; i++ )
|
for( i=0; w[i]; i++ )
|
||||||
{
|
{
|
||||||
wbitprint(w[i]);;
|
wbitprint(w[i]);;
|
||||||
//wprintf(L"%d ", w[i]);
|
//wprintf(L"%d ", w[i]);
|
||||||
}
|
}
|
||||||
wprintf(L"\n");
|
wprintf(L"\n");
|
||||||
|
|
||||||
for( i=0; n[i]; i++ )
|
for( i=0; n[i]; i++ )
|
||||||
{
|
{
|
||||||
bitprint(n[i]);;
|
bitprint(n[i]);;
|
||||||
//wprintf(L"%d ", n[i]);
|
//wprintf(L"%d ", n[i]);
|
||||||
}
|
}
|
||||||
wprintf(L"\n");
|
wprintf(L"\n");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
std::vector<char> sb;
|
std::vector<char> sb;
|
||||||
|
|
||||||
say( L"Testing wide/narrow string conversion" );
|
say( L"Testing wide/narrow string conversion" );
|
||||||
|
|
||||||
for( i=0; i<ESCAPE_TEST_COUNT; i++ )
|
for( i=0; i<ESCAPE_TEST_COUNT; i++ )
|
||||||
{
|
{
|
||||||
wchar_t *w;
|
wchar_t *w;
|
||||||
const char *o, *n;
|
const char *o, *n;
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
sb.clear();
|
sb.clear();
|
||||||
|
|
||||||
while( rand() % ESCAPE_TEST_LENGTH )
|
while( rand() % ESCAPE_TEST_LENGTH )
|
||||||
{
|
{
|
||||||
c = rand ();
|
c = rand ();
|
||||||
sb.push_back(c);
|
sb.push_back(c);
|
||||||
}
|
}
|
||||||
c = 0;
|
c = 0;
|
||||||
sb.push_back(c);
|
sb.push_back(c);
|
||||||
|
|
||||||
o = &sb.at(0);
|
o = &sb.at(0);
|
||||||
w = str2wcs(o);
|
w = str2wcs(o);
|
||||||
n = wcs2str(w);
|
n = wcs2str(w);
|
||||||
|
|
||||||
if( !o || !w || !n )
|
if( !o || !w || !n )
|
||||||
{
|
{
|
||||||
err( L"Line %d - Conversion cycle of string %s produced null pointer on %s", __LINE__, o, w?L"str2wcs":L"wcs2str" );
|
err( L"Line %d - Conversion cycle of string %s produced null pointer on %s", __LINE__, o, w?L"str2wcs":L"wcs2str" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( strcmp(o, n) )
|
if( strcmp(o, n) )
|
||||||
{
|
{
|
||||||
err( L"Line %d - %d: Conversion cycle of string %s produced different string %s", __LINE__, i, o, n );
|
err( L"Line %d - %d: Conversion cycle of string %s produced different string %s", __LINE__, i, o, n );
|
||||||
}
|
}
|
||||||
free( w );
|
free( w );
|
||||||
free( (void *)n );
|
free( (void *)n );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,63 +281,63 @@ static void test_convert()
|
||||||
*/
|
*/
|
||||||
static void test_tok()
|
static void test_tok()
|
||||||
{
|
{
|
||||||
tokenizer t;
|
tokenizer t;
|
||||||
|
|
||||||
say( L"Testing tokenizer" );
|
say( L"Testing tokenizer" );
|
||||||
|
|
||||||
|
|
||||||
say( L"Testing invalid input" );
|
say( L"Testing invalid input" );
|
||||||
tok_init( &t, 0, 0 );
|
tok_init( &t, 0, 0 );
|
||||||
|
|
||||||
if( tok_last_type( &t ) != TOK_ERROR )
|
if( tok_last_type( &t ) != TOK_ERROR )
|
||||||
{
|
{
|
||||||
err(L"Invalid input to tokenizer was undetected" );
|
err(L"Invalid input to tokenizer was undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
say( L"Testing use of broken tokenizer" );
|
say( L"Testing use of broken tokenizer" );
|
||||||
if( !tok_has_next( &t ) )
|
if( !tok_has_next( &t ) )
|
||||||
{
|
{
|
||||||
err( L"tok_has_next() should return 1 once on broken tokenizer" );
|
err( L"tok_has_next() should return 1 once on broken tokenizer" );
|
||||||
}
|
}
|
||||||
|
|
||||||
tok_next( &t );
|
tok_next( &t );
|
||||||
if( tok_last_type( &t ) != TOK_ERROR )
|
if( tok_last_type( &t ) != TOK_ERROR )
|
||||||
{
|
{
|
||||||
err(L"Invalid input to tokenizer was undetected" );
|
err(L"Invalid input to tokenizer was undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This should crash if there is a bug. No reliable way to detect otherwise.
|
This should crash if there is a bug. No reliable way to detect otherwise.
|
||||||
*/
|
*/
|
||||||
say( L"Test destruction of broken tokenizer" );
|
say( L"Test destruction of broken tokenizer" );
|
||||||
tok_destroy( &t );
|
tok_destroy( &t );
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
const wchar_t *str = L"string <redirection 2>&1 'nested \"quoted\" '(string containing subshells ){and,brackets}$as[$well (as variable arrays)] not_a_redirect^ ^ ^^is_a_redirect";
|
const wchar_t *str = L"string <redirection 2>&1 'nested \"quoted\" '(string containing subshells ){and,brackets}$as[$well (as variable arrays)] not_a_redirect^ ^ ^^is_a_redirect";
|
||||||
const int types[] =
|
const int types[] =
|
||||||
{
|
{
|
||||||
TOK_STRING, TOK_REDIRECT_IN, TOK_STRING, TOK_REDIRECT_FD, TOK_STRING, TOK_STRING, TOK_STRING, TOK_REDIRECT_OUT, TOK_REDIRECT_APPEND, TOK_STRING, TOK_END
|
TOK_STRING, TOK_REDIRECT_IN, TOK_STRING, TOK_REDIRECT_FD, TOK_STRING, TOK_STRING, TOK_STRING, TOK_REDIRECT_OUT, TOK_REDIRECT_APPEND, TOK_STRING, TOK_END
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
say( L"Test correct tokenization" );
|
say( L"Test correct tokenization" );
|
||||||
|
|
||||||
for( i=0, tok_init( &t, str, 0 ); i<(sizeof(types)/sizeof(int)); i++,tok_next( &t ) )
|
for( i=0, tok_init( &t, str, 0 ); i<(sizeof(types)/sizeof(int)); i++,tok_next( &t ) )
|
||||||
{
|
{
|
||||||
if( types[i] != tok_last_type( &t ) )
|
if( types[i] != tok_last_type( &t ) )
|
||||||
{
|
{
|
||||||
err( L"Tokenization error:");
|
err( L"Tokenization error:");
|
||||||
wprintf( L"Token number %d of string \n'%ls'\n, expected token type %ls, got token '%ls' of type %ls\n",
|
wprintf( L"Token number %d of string \n'%ls'\n, expected token type %ls, got token '%ls' of type %ls\n",
|
||||||
i+1,
|
i+1,
|
||||||
str,
|
str,
|
||||||
tok_get_desc(types[i]),
|
tok_get_desc(types[i]),
|
||||||
tok_last(&t),
|
tok_last(&t),
|
||||||
tok_get_desc(tok_last_type( &t )) );
|
tok_get_desc(tok_last_type( &t )) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_fork_helper(void *unused) {
|
static int test_fork_helper(void *unused) {
|
||||||
|
@ -397,73 +397,73 @@ static void test_fork(void) {
|
||||||
*/
|
*/
|
||||||
static void test_parser()
|
static void test_parser()
|
||||||
{
|
{
|
||||||
say( L"Testing parser" );
|
say( L"Testing parser" );
|
||||||
|
|
||||||
parser_t parser(PARSER_TYPE_GENERAL, true);
|
parser_t parser(PARSER_TYPE_GENERAL, true);
|
||||||
|
|
||||||
say( L"Testing null input to parser" );
|
say( L"Testing null input to parser" );
|
||||||
if( !parser.test( 0, 0, 0, 0 ) )
|
if( !parser.test( 0, 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Null input to parser.test undetected" );
|
err( L"Null input to parser.test undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
say( L"Testing block nesting" );
|
say( L"Testing block nesting" );
|
||||||
if( !parser.test( L"if; end", 0, 0, 0 ) )
|
if( !parser.test( L"if; end", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Incomplete if statement undetected" );
|
err( L"Incomplete if statement undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"if test; echo", 0, 0, 0 ) )
|
if( !parser.test( L"if test; echo", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Missing end undetected" );
|
err( L"Missing end undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"if test; end; end", 0, 0, 0 ) )
|
if( !parser.test( L"if test; end; end", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Unbalanced end undetected" );
|
err( L"Unbalanced end undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
say( L"Testing detection of invalid use of builtin commands" );
|
say( L"Testing detection of invalid use of builtin commands" );
|
||||||
if( !parser.test( L"case foo", 0, 0, 0 ) )
|
if( !parser.test( L"case foo", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'case' command outside of block context undetected" );
|
err( L"'case' command outside of block context undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"switch ggg; if true; case foo;end;end", 0, 0, 0 ) )
|
if( !parser.test( L"switch ggg; if true; case foo;end;end", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'case' command outside of switch block context undetected" );
|
err( L"'case' command outside of switch block context undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"else", 0, 0, 0 ) )
|
if( !parser.test( L"else", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'else' command outside of conditional block context undetected" );
|
err( L"'else' command outside of conditional block context undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"else if", 0, 0, 0 ) )
|
if( !parser.test( L"else if", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'else if' command outside of conditional block context undetected" );
|
err( L"'else if' command outside of conditional block context undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"if false; else if; end", 0, 0, 0 ) )
|
if( !parser.test( L"if false; else if; end", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'else if' missing command undetected" );
|
err( L"'else if' missing command undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !parser.test( L"break", 0, 0, 0 ) )
|
if( !parser.test( L"break", 0, 0, 0 ) )
|
||||||
{
|
{
|
||||||
err( L"'break' command outside of loop block context undetected" );
|
err( L"'break' command outside of loop block context undetected" );
|
||||||
}
|
}
|
||||||
if( !parser.test( L"exec ls|less", 0, 0, 0 ) || !parser.test( L"echo|return", 0, 0, 0 ))
|
if( !parser.test( L"exec ls|less", 0, 0, 0 ) || !parser.test( L"echo|return", 0, 0, 0 ))
|
||||||
{
|
{
|
||||||
err( L"Invalid pipe command undetected" );
|
err( L"Invalid pipe command undetected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
say( L"Testing basic evaluation" );
|
say( L"Testing basic evaluation" );
|
||||||
#if 0
|
#if 0
|
||||||
/* This fails now since the parser takes a wcstring&, and NULL converts to wchar_t * converts to wcstring which crashes (thanks C++) */
|
/* This fails now since the parser takes a wcstring&, and NULL converts to wchar_t * converts to wcstring which crashes (thanks C++) */
|
||||||
if( !parser.eval( 0, 0, TOP ) )
|
if( !parser.eval( 0, 0, TOP ) )
|
||||||
{
|
{
|
||||||
err( L"Null input when evaluating undetected" );
|
err( L"Null input when evaluating undetected" );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( !parser.eval( L"ls", io_chain_t(), WHILE ) )
|
if( !parser.eval( L"ls", io_chain_t(), WHILE ) )
|
||||||
{
|
{
|
||||||
err( L"Invalid block mode when evaluating undetected" );
|
err( L"Invalid block mode when evaluating undetected" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class lru_node_test_t : public lru_node_t {
|
class lru_node_test_t : public lru_node_t {
|
||||||
|
@ -516,16 +516,16 @@ static void test_lru(void) {
|
||||||
|
|
||||||
static int expand_test( const wchar_t *in, int flags, ... )
|
static int expand_test( const wchar_t *in, int flags, ... )
|
||||||
{
|
{
|
||||||
std::vector<completion_t> output;
|
std::vector<completion_t> output;
|
||||||
va_list va;
|
va_list va;
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
int res=1;
|
int res=1;
|
||||||
wchar_t *arg;
|
wchar_t *arg;
|
||||||
|
|
||||||
if( expand_string( in, output, flags) )
|
if( expand_string( in, output, flags) )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (size_t idx=0; idx < output.size(); idx++)
|
for (size_t idx=0; idx < output.size(); idx++)
|
||||||
|
@ -534,27 +534,27 @@ static int expand_test( const wchar_t *in, int flags, ... )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
va_start( va, flags );
|
va_start( va, flags );
|
||||||
|
|
||||||
while( (arg=va_arg(va, wchar_t *) )!= 0 )
|
while( (arg=va_arg(va, wchar_t *) )!= 0 )
|
||||||
{
|
{
|
||||||
if( output.size() == i )
|
if( output.size() == i )
|
||||||
{
|
{
|
||||||
res=0;
|
res=0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.at(i).completion != arg)
|
if (output.at(i).completion != arg)
|
||||||
{
|
{
|
||||||
res=0;
|
res=0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
va_end( va );
|
va_end( va );
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,36 +563,36 @@ static int expand_test( const wchar_t *in, int flags, ... )
|
||||||
*/
|
*/
|
||||||
static void test_expand()
|
static void test_expand()
|
||||||
{
|
{
|
||||||
say( L"Testing parameter expansion" );
|
say( L"Testing parameter expansion" );
|
||||||
|
|
||||||
if( !expand_test( L"foo", 0, L"foo", 0 ))
|
if( !expand_test( L"foo", 0, L"foo", 0 ))
|
||||||
{
|
{
|
||||||
err( L"Strings do not expand to themselves" );
|
err( L"Strings do not expand to themselves" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !expand_test( L"a{b,c,d}e", 0, L"abe", L"ace", L"ade", 0 ) )
|
if( !expand_test( L"a{b,c,d}e", 0, L"abe", L"ace", L"ade", 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Bracket expansion is broken" );
|
err( L"Bracket expansion is broken" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !expand_test( L"a*", EXPAND_SKIP_WILDCARDS, L"a*", 0 ) )
|
if( !expand_test( L"a*", EXPAND_SKIP_WILDCARDS, L"a*", 0 ) )
|
||||||
{
|
{
|
||||||
err( L"Cannot skip wildcard expansion" );
|
err( L"Cannot skip wildcard expansion" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (system("mkdir -p /tmp/fish_expand_test/")) err(L"mkdir failed");
|
if (system("mkdir -p /tmp/fish_expand_test/")) err(L"mkdir failed");
|
||||||
if (system("touch /tmp/fish_expand_test/.foo")) err(L"touch failed");
|
if (system("touch /tmp/fish_expand_test/.foo")) err(L"touch failed");
|
||||||
if (system("touch /tmp/fish_expand_test/bar")) err(L"touch failed");
|
if (system("touch /tmp/fish_expand_test/bar")) err(L"touch failed");
|
||||||
|
|
||||||
// This is checking that .* does NOT match . and .. (https://github.com/fish-shell/fish-shell/issues/270). But it does have to match literal components (e.g. "./*" has to match the same as "*"
|
// This is checking that .* does NOT match . and .. (https://github.com/fish-shell/fish-shell/issues/270). But it does have to match literal components (e.g. "./*" has to match the same as "*"
|
||||||
if (! expand_test( L"/tmp/fish_expand_test/.*", 0, L"/tmp/fish_expand_test/.foo", 0 ))
|
if (! expand_test( L"/tmp/fish_expand_test/.*", 0, L"/tmp/fish_expand_test/.foo", 0 ))
|
||||||
{
|
{
|
||||||
err( L"Expansion not correctly handling dotfiles" );
|
err( L"Expansion not correctly handling dotfiles" );
|
||||||
}
|
}
|
||||||
if (! expand_test( L"/tmp/fish_expand_test/./.*", 0, L"/tmp/fish_expand_test/./.foo", 0 ))
|
if (! expand_test( L"/tmp/fish_expand_test/./.*", 0, L"/tmp/fish_expand_test/./.foo", 0 ))
|
||||||
{
|
{
|
||||||
err( L"Expansion not correctly handling literal path components in dotfiles" );
|
err( L"Expansion not correctly handling literal path components in dotfiles" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//system("rm -Rf /tmp/fish_expand_test");
|
//system("rm -Rf /tmp/fish_expand_test");
|
||||||
}
|
}
|
||||||
|
@ -600,21 +600,21 @@ static void test_expand()
|
||||||
/** Test path functions */
|
/** Test path functions */
|
||||||
static void test_path()
|
static void test_path()
|
||||||
{
|
{
|
||||||
say( L"Testing path functions" );
|
say( L"Testing path functions" );
|
||||||
|
|
||||||
wcstring path = L"//foo//////bar/";
|
wcstring path = L"//foo//////bar/";
|
||||||
wcstring canon = path;
|
wcstring canon = path;
|
||||||
path_make_canonical(canon);
|
path_make_canonical(canon);
|
||||||
if( canon != L"/foo/bar" )
|
if( canon != L"/foo/bar" )
|
||||||
{
|
{
|
||||||
err( L"Bug in canonical PATH code" );
|
err( L"Bug in canonical PATH code" );
|
||||||
}
|
}
|
||||||
|
|
||||||
path = L"/";
|
path = L"/";
|
||||||
path_make_canonical(path);
|
path_make_canonical(path);
|
||||||
if (path != L"/")
|
if (path != L"/")
|
||||||
{
|
{
|
||||||
err( L"Bug in canonical PATH code" );
|
err( L"Bug in canonical PATH code" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,64 +845,64 @@ static void test_autosuggest_suggest_special() {
|
||||||
*/
|
*/
|
||||||
void perf_complete()
|
void perf_complete()
|
||||||
{
|
{
|
||||||
wchar_t c;
|
wchar_t c;
|
||||||
std::vector<completion_t> out;
|
std::vector<completion_t> out;
|
||||||
long long t1, t2;
|
long long t1, t2;
|
||||||
int matches=0;
|
int matches=0;
|
||||||
double t;
|
double t;
|
||||||
wchar_t str[3]=
|
wchar_t str[3]=
|
||||||
{
|
{
|
||||||
0, 0, 0
|
0, 0, 0
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
||||||
say( L"Testing completion performance" );
|
say( L"Testing completion performance" );
|
||||||
|
|
||||||
reader_push(L"");
|
reader_push(L"");
|
||||||
say( L"Here we go" );
|
say( L"Here we go" );
|
||||||
|
|
||||||
t1 = get_time();
|
t1 = get_time();
|
||||||
|
|
||||||
|
|
||||||
for( c=L'a'; c<=L'z'; c++ )
|
for( c=L'a'; c<=L'z'; c++ )
|
||||||
{
|
{
|
||||||
str[0]=c;
|
str[0]=c;
|
||||||
reader_set_buffer( str, 0 );
|
reader_set_buffer( str, 0 );
|
||||||
|
|
||||||
complete( str, out, COMPLETE_DEFAULT, NULL );
|
complete( str, out, COMPLETE_DEFAULT, NULL );
|
||||||
|
|
||||||
matches += out.size();
|
matches += out.size();
|
||||||
out.clear();
|
out.clear();
|
||||||
}
|
}
|
||||||
t2=get_time();
|
t2=get_time();
|
||||||
|
|
||||||
t = (double)(t2-t1)/(1000000*26);
|
t = (double)(t2-t1)/(1000000*26);
|
||||||
|
|
||||||
say( L"One letter command completion took %f seconds per completion, %f microseconds/match", t, (double)(t2-t1)/matches );
|
say( L"One letter command completion took %f seconds per completion, %f microseconds/match", t, (double)(t2-t1)/matches );
|
||||||
|
|
||||||
matches=0;
|
matches=0;
|
||||||
t1 = get_time();
|
t1 = get_time();
|
||||||
for( i=0; i<LAPS; i++ )
|
for( i=0; i<LAPS; i++ )
|
||||||
{
|
{
|
||||||
str[0]='a'+(rand()%26);
|
str[0]='a'+(rand()%26);
|
||||||
str[1]='a'+(rand()%26);
|
str[1]='a'+(rand()%26);
|
||||||
|
|
||||||
reader_set_buffer( str, 0 );
|
reader_set_buffer( str, 0 );
|
||||||
|
|
||||||
complete( str, out, COMPLETE_DEFAULT, NULL );
|
complete( str, out, COMPLETE_DEFAULT, NULL );
|
||||||
|
|
||||||
matches += out.size();
|
matches += out.size();
|
||||||
out.clear();
|
out.clear();
|
||||||
}
|
}
|
||||||
t2=get_time();
|
t2=get_time();
|
||||||
|
|
||||||
t = (double)(t2-t1)/(1000000*LAPS);
|
t = (double)(t2-t1)/(1000000*LAPS);
|
||||||
|
|
||||||
say( L"Two letter command completion took %f seconds per completion, %f microseconds/match", t, (double)(t2-t1)/matches );
|
say( L"Two letter command completion took %f seconds per completion, %f microseconds/match", t, (double)(t2-t1)/matches );
|
||||||
|
|
||||||
reader_pop();
|
reader_pop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,33 +1212,33 @@ void history_tests_t::test_history_formats(void) {
|
||||||
*/
|
*/
|
||||||
int main( int argc, char **argv )
|
int main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
setlocale( LC_ALL, "" );
|
setlocale( LC_ALL, "" );
|
||||||
srand( time( 0 ) );
|
srand( time( 0 ) );
|
||||||
configure_thread_assertions_for_testing();
|
configure_thread_assertions_for_testing();
|
||||||
|
|
||||||
program_name=L"(ignore)";
|
program_name=L"(ignore)";
|
||||||
|
|
||||||
say( L"Testing low-level functionality");
|
say( L"Testing low-level functionality");
|
||||||
say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." );
|
say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." );
|
||||||
set_main_thread();
|
set_main_thread();
|
||||||
setup_fork_guards();
|
setup_fork_guards();
|
||||||
proc_init();
|
proc_init();
|
||||||
event_init();
|
event_init();
|
||||||
function_init();
|
function_init();
|
||||||
builtin_init();
|
builtin_init();
|
||||||
reader_init();
|
reader_init();
|
||||||
env_init();
|
env_init();
|
||||||
|
|
||||||
test_format();
|
test_format();
|
||||||
test_escape();
|
test_escape();
|
||||||
test_convert();
|
test_convert();
|
||||||
test_tok();
|
test_tok();
|
||||||
test_fork();
|
test_fork();
|
||||||
test_parser();
|
test_parser();
|
||||||
test_lru();
|
test_lru();
|
||||||
test_expand();
|
test_expand();
|
||||||
test_test();
|
test_test();
|
||||||
test_path();
|
test_path();
|
||||||
test_is_potential_path();
|
test_is_potential_path();
|
||||||
test_colors();
|
test_colors();
|
||||||
test_autosuggest_suggest_special();
|
test_autosuggest_suggest_special();
|
||||||
|
@ -1246,19 +1246,19 @@ int main( int argc, char **argv )
|
||||||
history_tests_t::test_history_merge();
|
history_tests_t::test_history_merge();
|
||||||
history_tests_t::test_history_formats();
|
history_tests_t::test_history_formats();
|
||||||
|
|
||||||
say( L"Encountered %d errors in low-level tests", err_count );
|
say( L"Encountered %d errors in low-level tests", err_count );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Skip performance tests for now, since they seem to hang when running from inside make (?)
|
Skip performance tests for now, since they seem to hang when running from inside make (?)
|
||||||
*/
|
*/
|
||||||
// say( L"Testing performance" );
|
// say( L"Testing performance" );
|
||||||
// perf_complete();
|
// perf_complete();
|
||||||
|
|
||||||
env_destroy();
|
env_destroy();
|
||||||
reader_destroy();
|
reader_destroy();
|
||||||
builtin_destroy();
|
builtin_destroy();
|
||||||
wutil_destroy();
|
wutil_destroy();
|
||||||
event_destroy();
|
event_destroy();
|
||||||
proc_destroy();
|
proc_destroy();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
104
function.cpp
104
function.cpp
|
@ -1,10 +1,10 @@
|
||||||
/** \file function.c
|
/** \file function.c
|
||||||
|
|
||||||
Prototypes for functions for storing and retrieving function
|
Prototypes for functions for storing and retrieving function
|
||||||
information. These functions also take care of autoloading
|
information. These functions also take care of autoloading
|
||||||
functions in the $fish_function_path. Actual function evaluation
|
functions in the $fish_function_path. Actual function evaluation
|
||||||
is taken care of by the parser and to some degree the builtin
|
is taken care of by the parser and to some degree the builtin
|
||||||
handling library.
|
handling library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -89,18 +89,18 @@ static int load( const wcstring &name )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
bool was_autoload = is_autoload;
|
bool was_autoload = is_autoload;
|
||||||
int res;
|
int res;
|
||||||
function_map_t::iterator iter = loaded_functions.find(name);
|
function_map_t::iterator iter = loaded_functions.find(name);
|
||||||
if( iter != loaded_functions.end() && !iter->second.is_autoload ) {
|
if( iter != loaded_functions.end() && !iter->second.is_autoload ) {
|
||||||
/* We have a non-autoload version already */
|
/* We have a non-autoload version already */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_autoload = true;
|
is_autoload = true;
|
||||||
res = function_autoloader.load( name, true );
|
res = function_autoloader.load( name, true );
|
||||||
is_autoload = was_autoload;
|
is_autoload = was_autoload;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,41 +109,41 @@ static int load( const wcstring &name )
|
||||||
*/
|
*/
|
||||||
static void autoload_names( std::set<wcstring> &names, int get_hidden )
|
static void autoload_names( std::set<wcstring> &names, int get_hidden )
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
const env_var_t path_var_wstr = env_get_string( L"fish_function_path" );
|
const env_var_t path_var_wstr = env_get_string( L"fish_function_path" );
|
||||||
if (path_var_wstr.missing())
|
if (path_var_wstr.missing())
|
||||||
return;
|
return;
|
||||||
const wchar_t *path_var = path_var_wstr.c_str();
|
const wchar_t *path_var = path_var_wstr.c_str();
|
||||||
|
|
||||||
wcstring_list_t path_list;
|
wcstring_list_t path_list;
|
||||||
|
|
||||||
tokenize_variable_array( path_var, path_list );
|
tokenize_variable_array( path_var, path_list );
|
||||||
for( i=0; i<path_list.size(); i++ )
|
for( i=0; i<path_list.size(); i++ )
|
||||||
{
|
{
|
||||||
const wcstring &ndir_str = path_list.at(i);
|
const wcstring &ndir_str = path_list.at(i);
|
||||||
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
|
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
|
||||||
DIR *dir = wopendir( ndir );
|
DIR *dir = wopendir( ndir );
|
||||||
if( !dir )
|
if( !dir )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
wcstring name;
|
wcstring name;
|
||||||
while (wreaddir(dir, name))
|
while (wreaddir(dir, name))
|
||||||
{
|
{
|
||||||
const wchar_t *fn = name.c_str();
|
const wchar_t *fn = name.c_str();
|
||||||
const wchar_t *suffix;
|
const wchar_t *suffix;
|
||||||
if( !get_hidden && fn[0] == L'_' )
|
if( !get_hidden && fn[0] == L'_' )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
suffix = wcsrchr( fn, L'.' );
|
suffix = wcsrchr( fn, L'.' );
|
||||||
if( suffix && (wcscmp( suffix, L".fish" ) == 0 ) )
|
if( suffix && (wcscmp( suffix, L".fish" ) == 0 ) )
|
||||||
{
|
{
|
||||||
wcstring name(fn, suffix - fn);
|
wcstring name(fn, suffix - fn);
|
||||||
names.insert(name);
|
names.insert(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void function_init()
|
void function_init()
|
||||||
|
@ -182,12 +182,12 @@ void function_add( const function_data_t &data, const parser_t &parser )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
CHECK( ! data.name.empty(), );
|
CHECK( ! data.name.empty(), );
|
||||||
CHECK( data.definition, );
|
CHECK( data.definition, );
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
|
|
||||||
/* Remove the old function */
|
/* Remove the old function */
|
||||||
function_remove( data.name );
|
function_remove( data.name );
|
||||||
|
|
||||||
|
|
||||||
/* Create and store a new function */
|
/* Create and store a new function */
|
||||||
|
@ -197,16 +197,16 @@ void function_add( const function_data_t &data, const parser_t &parser )
|
||||||
loaded_functions.insert(new_pair);
|
loaded_functions.insert(new_pair);
|
||||||
|
|
||||||
/* Add event handlers */
|
/* Add event handlers */
|
||||||
for( std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter )
|
for( std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter )
|
||||||
{
|
{
|
||||||
event_add_handler( &*iter );
|
event_add_handler( &*iter );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int function_exists( const wcstring &cmd )
|
int function_exists( const wcstring &cmd )
|
||||||
{
|
{
|
||||||
if( parser_keywords_is_reserved(cmd) )
|
if( parser_keywords_is_reserved(cmd) )
|
||||||
return 0;
|
return 0;
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
load(cmd);
|
load(cmd);
|
||||||
return loaded_functions.find(cmd) != loaded_functions.end();
|
return loaded_functions.find(cmd) != loaded_functions.end();
|
||||||
|
@ -214,8 +214,8 @@ int function_exists( const wcstring &cmd )
|
||||||
|
|
||||||
int function_exists_no_autoload( const wcstring &cmd, const env_vars_snapshot_t &vars )
|
int function_exists_no_autoload( const wcstring &cmd, const env_vars_snapshot_t &vars )
|
||||||
{
|
{
|
||||||
if( parser_keywords_is_reserved(cmd) )
|
if( parser_keywords_is_reserved(cmd) )
|
||||||
return 0;
|
return 0;
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
return loaded_functions.find(cmd) != loaded_functions.end() || function_autoloader.can_load(cmd, vars);
|
return loaded_functions.find(cmd) != loaded_functions.end() || function_autoloader.can_load(cmd, vars);
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ static bool function_remove_ignore_autoload(const wcstring &name)
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
bool erased = (loaded_functions.erase(name) > 0);
|
bool erased = (loaded_functions.erase(name) > 0);
|
||||||
|
|
||||||
if (erased) {
|
if (erased) {
|
||||||
event_t ev(EVENT_ANY);
|
event_t ev(EVENT_ANY);
|
||||||
ev.function_name=name;
|
ev.function_name=name;
|
||||||
event_remove( &ev );
|
event_remove( &ev );
|
||||||
|
@ -293,7 +293,7 @@ bool function_get_desc(const wcstring &name, wcstring *out_desc)
|
||||||
|
|
||||||
void function_set_desc(const wcstring &name, const wcstring &desc)
|
void function_set_desc(const wcstring &name, const wcstring &desc)
|
||||||
{
|
{
|
||||||
load(name);
|
load(name);
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
function_map_t::iterator iter = loaded_functions.find(name);
|
function_map_t::iterator iter = loaded_functions.find(name);
|
||||||
if (iter != loaded_functions.end()) {
|
if (iter != loaded_functions.end()) {
|
||||||
|
@ -307,19 +307,19 @@ bool function_copy(const wcstring &name, const wcstring &new_name)
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
function_map_t::const_iterator iter = loaded_functions.find(name);
|
function_map_t::const_iterator iter = loaded_functions.find(name);
|
||||||
if (iter != loaded_functions.end()) {
|
if (iter != loaded_functions.end()) {
|
||||||
// This new instance of the function shouldn't be tied to the definition file of the original, so pass NULL filename, etc.
|
// This new instance of the function shouldn't be tied to the definition file of the original, so pass NULL filename, etc.
|
||||||
const function_map_t::value_type new_pair(new_name, function_info_t(iter->second, NULL, 0, false));
|
const function_map_t::value_type new_pair(new_name, function_info_t(iter->second, NULL, 0, false));
|
||||||
loaded_functions.insert(new_pair);
|
loaded_functions.insert(new_pair);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring_list_t function_get_names(int get_hidden)
|
wcstring_list_t function_get_names(int get_hidden)
|
||||||
{
|
{
|
||||||
std::set<wcstring> names;
|
std::set<wcstring> names;
|
||||||
scoped_lock lock(functions_lock);
|
scoped_lock lock(functions_lock);
|
||||||
autoload_names(names, get_hidden);
|
autoload_names(names, get_hidden);
|
||||||
|
|
||||||
function_map_t::const_iterator iter;
|
function_map_t::const_iterator iter;
|
||||||
for (iter = loaded_functions.begin(); iter != loaded_functions.end(); ++iter) {
|
for (iter = loaded_functions.begin(); iter != loaded_functions.end(); ++iter) {
|
||||||
|
|
72
function.h
72
function.h
|
@ -1,10 +1,10 @@
|
||||||
/** \file function.h
|
/** \file function.h
|
||||||
|
|
||||||
Prototypes for functions for storing and retrieving function
|
Prototypes for functions for storing and retrieving function
|
||||||
information. These functions also take care of autoloading
|
information. These functions also take care of autoloading
|
||||||
functions in the $fish_function_path. Actual function evaluation
|
functions in the $fish_function_path. Actual function evaluation
|
||||||
is taken care of by the parser and to some degree the builtin
|
is taken care of by the parser and to some degree the builtin
|
||||||
handling library.
|
handling library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_FUNCTION_H
|
#ifndef FISH_FUNCTION_H
|
||||||
|
@ -28,31 +28,31 @@ class env_vars_snapshot_t;
|
||||||
*/
|
*/
|
||||||
struct function_data_t
|
struct function_data_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
Name of function
|
Name of function
|
||||||
*/
|
*/
|
||||||
wcstring name;
|
wcstring name;
|
||||||
/**
|
/**
|
||||||
Description of function
|
Description of function
|
||||||
*/
|
*/
|
||||||
wcstring description;
|
wcstring description;
|
||||||
/**
|
/**
|
||||||
Function definition
|
Function definition
|
||||||
*/
|
*/
|
||||||
wchar_t *definition;
|
wchar_t *definition;
|
||||||
/**
|
/**
|
||||||
List of all event handlers for this function
|
List of all event handlers for this function
|
||||||
*/
|
*/
|
||||||
std::vector<event_t> events;
|
std::vector<event_t> events;
|
||||||
/**
|
/**
|
||||||
List of all named arguments for this function
|
List of all named arguments for this function
|
||||||
*/
|
*/
|
||||||
wcstring_list_t named_arguments;
|
wcstring_list_t named_arguments;
|
||||||
/**
|
/**
|
||||||
Set to non-zero if invoking this function shadows the variables
|
Set to non-zero if invoking this function shadows the variables
|
||||||
of the underlying function.
|
of the underlying function.
|
||||||
*/
|
*/
|
||||||
int shadows;
|
int shadows;
|
||||||
};
|
};
|
||||||
|
|
||||||
class function_info_t {
|
class function_info_t {
|
||||||
|
@ -69,20 +69,20 @@ public:
|
||||||
/** Function description. Only the description may be changed after the function is created. */
|
/** Function description. Only the description may be changed after the function is created. */
|
||||||
wcstring description;
|
wcstring description;
|
||||||
|
|
||||||
/** File where this function was defined (intern'd string) */
|
/** File where this function was defined (intern'd string) */
|
||||||
const wchar_t * const definition_file;
|
const wchar_t * const definition_file;
|
||||||
|
|
||||||
/** Line where definition started */
|
/** Line where definition started */
|
||||||
const int definition_offset;
|
const int definition_offset;
|
||||||
|
|
||||||
/** List of all named arguments for this function */
|
/** List of all named arguments for this function */
|
||||||
const wcstring_list_t named_arguments;
|
const wcstring_list_t named_arguments;
|
||||||
|
|
||||||
/** Flag for specifying that this function was automatically loaded */
|
/** Flag for specifying that this function was automatically loaded */
|
||||||
const bool is_autoload;
|
const bool is_autoload;
|
||||||
|
|
||||||
/** Set to true if invoking this function shadows the variables of the underlying function. */
|
/** Set to true if invoking this function shadows the variables of the underlying function. */
|
||||||
const bool shadows;
|
const bool shadows;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
1430
highlight.cpp
1430
highlight.cpp
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
/** \file highlight.h
|
/** \file highlight.h
|
||||||
Prototypes for functions for syntax highlighting
|
Prototypes for functions for syntax highlighting
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_HIGHLIGHT_H
|
#ifndef FISH_HIGHLIGHT_H
|
||||||
|
|
188
history.cpp
188
history.cpp
|
@ -1,5 +1,5 @@
|
||||||
/** \file history.c
|
/** \file history.c
|
||||||
History functions, part of the user interface.
|
History functions, part of the user interface.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -339,46 +339,46 @@ static size_t offset_of_next_item_fish_1_x(const char *begin, size_t mmap_length
|
||||||
if (mmap_length == 0 || *inout_cursor >= mmap_length)
|
if (mmap_length == 0 || *inout_cursor >= mmap_length)
|
||||||
return (size_t)(-1);
|
return (size_t)(-1);
|
||||||
|
|
||||||
const char *end = begin + mmap_length;
|
const char *end = begin + mmap_length;
|
||||||
const char *pos;
|
const char *pos;
|
||||||
|
|
||||||
bool ignore_newline = false;
|
bool ignore_newline = false;
|
||||||
bool do_push = true;
|
bool do_push = true;
|
||||||
bool all_done = false;
|
bool all_done = false;
|
||||||
|
|
||||||
size_t result = *inout_cursor;
|
size_t result = *inout_cursor;
|
||||||
for( pos = begin + *inout_cursor; pos < end && ! all_done; pos++ )
|
for( pos = begin + *inout_cursor; pos < end && ! all_done; pos++ )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( do_push )
|
if( do_push )
|
||||||
{
|
{
|
||||||
ignore_newline = (*pos == '#');
|
ignore_newline = (*pos == '#');
|
||||||
do_push = false;
|
do_push = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( *pos )
|
switch( *pos )
|
||||||
{
|
{
|
||||||
case '\\':
|
case '\\':
|
||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
{
|
{
|
||||||
if( ignore_newline )
|
if( ignore_newline )
|
||||||
{
|
{
|
||||||
ignore_newline = false;
|
ignore_newline = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Note: pos will be left pointing just after this newline, because of the ++ in the loop */
|
/* Note: pos will be left pointing just after this newline, because of the ++ in the loop */
|
||||||
all_done = true;
|
all_done = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*inout_cursor = (pos - begin);
|
*inout_cursor = (pos - begin);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ void history_t::add(const history_item_t &item)
|
||||||
/* This might be a good candidate for moving to a background thread */
|
/* This might be a good candidate for moving to a background thread */
|
||||||
if((now > save_timestamp + SAVE_INTERVAL) || (unsaved_item_count >= SAVE_COUNT)) {
|
if((now > save_timestamp + SAVE_INTERVAL) || (unsaved_item_count >= SAVE_COUNT)) {
|
||||||
time_profiler_t profiler("save_internal");
|
time_profiler_t profiler("save_internal");
|
||||||
this->save_internal();
|
this->save_internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -660,21 +660,21 @@ history_item_t history_t::decode_item(const char *base, size_t len, history_file
|
||||||
static wcstring history_unescape_newlines_fish_1_x( const wcstring &in_str )
|
static wcstring history_unescape_newlines_fish_1_x( const wcstring &in_str )
|
||||||
{
|
{
|
||||||
wcstring out;
|
wcstring out;
|
||||||
for (const wchar_t *in = in_str.c_str(); *in; in++)
|
for (const wchar_t *in = in_str.c_str(); *in; in++)
|
||||||
{
|
{
|
||||||
if( *in == L'\\' )
|
if( *in == L'\\' )
|
||||||
{
|
{
|
||||||
if( *(in+1)!= L'\n')
|
if( *(in+1)!= L'\n')
|
||||||
{
|
{
|
||||||
out.push_back(*in);
|
out.push_back(*in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.push_back(*in);
|
out.push_back(*in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -805,25 +805,25 @@ static bool map_file(const wcstring &name, const char **out_map_start, size_t *o
|
||||||
if (! filename.empty())
|
if (! filename.empty())
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
if((fd = wopen_cloexec(filename, O_RDONLY)) > 0)
|
if((fd = wopen_cloexec(filename, O_RDONLY)) > 0)
|
||||||
{
|
{
|
||||||
off_t len = lseek( fd, 0, SEEK_END );
|
off_t len = lseek( fd, 0, SEEK_END );
|
||||||
if(len != (off_t)-1)
|
if(len != (off_t)-1)
|
||||||
{
|
{
|
||||||
size_t mmap_length = (size_t)len;
|
size_t mmap_length = (size_t)len;
|
||||||
if(lseek(fd, 0, SEEK_SET) == 0)
|
if(lseek(fd, 0, SEEK_SET) == 0)
|
||||||
{
|
{
|
||||||
char *mmap_start;
|
char *mmap_start;
|
||||||
if ((mmap_start = (char *)mmap(0, mmap_length, PROT_READ, MAP_PRIVATE, fd, 0)) != MAP_FAILED)
|
if ((mmap_start = (char *)mmap(0, mmap_length, PROT_READ, MAP_PRIVATE, fd, 0)) != MAP_FAILED)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
*out_map_start = mmap_start;
|
*out_map_start = mmap_start;
|
||||||
*out_map_len = mmap_length;
|
*out_map_len = mmap_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close( fd );
|
close( fd );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -835,9 +835,9 @@ bool history_t::load_old_if_needed(void)
|
||||||
|
|
||||||
|
|
||||||
// PCA not sure why signals were blocked here
|
// PCA not sure why signals were blocked here
|
||||||
//signal_block();
|
//signal_block();
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (map_file(name, &mmap_start, &mmap_length)) {
|
if (map_file(name, &mmap_start, &mmap_length)) {
|
||||||
// Here we've mapped the file
|
// Here we've mapped the file
|
||||||
ok = true;
|
ok = true;
|
||||||
|
@ -845,7 +845,7 @@ bool history_t::load_old_if_needed(void)
|
||||||
this->populate_from_mmap();
|
this->populate_from_mmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
//signal_unblock();
|
//signal_unblock();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,11 +1022,11 @@ void history_t::save_internal()
|
||||||
/* Compact our new items so we don't have duplicates */
|
/* Compact our new items so we don't have duplicates */
|
||||||
this->compact_new_items();
|
this->compact_new_items();
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
wcstring tmp_name = history_filename(name, L".tmp");
|
wcstring tmp_name = history_filename(name, L".tmp");
|
||||||
if( ! tmp_name.empty() )
|
if( ! tmp_name.empty() )
|
||||||
{
|
{
|
||||||
/* Make an LRU cache to save only the last N elements */
|
/* Make an LRU cache to save only the last N elements */
|
||||||
history_lru_cache_t lru(HISTORY_SAVE_MAX);
|
history_lru_cache_t lru(HISTORY_SAVE_MAX);
|
||||||
|
|
||||||
|
@ -1078,8 +1078,8 @@ void history_t::save_internal()
|
||||||
signal_block();
|
signal_block();
|
||||||
|
|
||||||
FILE *out;
|
FILE *out;
|
||||||
if( (out=wfopen( tmp_name, "w" ) ) )
|
if( (out=wfopen( tmp_name, "w" ) ) )
|
||||||
{
|
{
|
||||||
/* Write them out */
|
/* Write them out */
|
||||||
for (history_lru_cache_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) {
|
for (history_lru_cache_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) {
|
||||||
const history_lru_node_t *node = *iter;
|
const history_lru_node_t *node = *iter;
|
||||||
|
@ -1089,20 +1089,20 @@ void history_t::save_internal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fclose( out ) || !ok )
|
if( fclose( out ) || !ok )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This message does not have high enough priority to
|
This message does not have high enough priority to
|
||||||
be shown by default.
|
be shown by default.
|
||||||
*/
|
*/
|
||||||
debug( 2, L"Error when writing history file" );
|
debug( 2, L"Error when writing history file" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wcstring new_name = history_filename(name, wcstring());
|
wcstring new_name = history_filename(name, wcstring());
|
||||||
wrename(tmp_name, new_name);
|
wrename(tmp_name, new_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signal_unblock();
|
signal_unblock();
|
||||||
|
|
||||||
|
@ -1111,13 +1111,13 @@ void history_t::save_internal()
|
||||||
|
|
||||||
/* We've saved everything, so we have no more unsaved items */
|
/* We've saved everything, so we have no more unsaved items */
|
||||||
unsaved_item_count = 0;
|
unsaved_item_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ok )
|
if( ok )
|
||||||
{
|
{
|
||||||
/* Our history has been written to the file, so clear our state so we can re-reference the file. */
|
/* Our history has been written to the file, so clear our state so we can re-reference the file. */
|
||||||
this->clear_file_state();
|
this->clear_file_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void history_t::save(void)
|
void history_t::save(void)
|
||||||
|
@ -1229,9 +1229,9 @@ void history_destroy()
|
||||||
|
|
||||||
void history_sanity_check()
|
void history_sanity_check()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
No sanity checking implemented yet...
|
No sanity checking implemented yet...
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_detection_context_t::perform_file_detection(bool test_all) {
|
int file_detection_context_t::perform_file_detection(bool test_all) {
|
||||||
|
|
36
history.h
36
history.h
|
@ -35,11 +35,11 @@ class history_item_t {
|
||||||
/** Attempts to merge two compatible history items together */
|
/** Attempts to merge two compatible history items together */
|
||||||
bool merge(const history_item_t &item);
|
bool merge(const history_item_t &item);
|
||||||
|
|
||||||
/** The actual contents of the entry */
|
/** The actual contents of the entry */
|
||||||
wcstring contents;
|
wcstring contents;
|
||||||
|
|
||||||
/** Original creation time for the entry */
|
/** Original creation time for the entry */
|
||||||
time_t creation_timestamp;
|
time_t creation_timestamp;
|
||||||
|
|
||||||
/** Paths that we require to be valid for this item to be autosuggested */
|
/** Paths that we require to be valid for this item to be autosuggested */
|
||||||
path_list_t required_paths;
|
path_list_t required_paths;
|
||||||
|
@ -91,23 +91,23 @@ private:
|
||||||
/** Internal function */
|
/** Internal function */
|
||||||
void clear_file_state();
|
void clear_file_state();
|
||||||
|
|
||||||
/** The name of this list. Used for picking a suitable filename and for switching modes. */
|
/** The name of this list. Used for picking a suitable filename and for switching modes. */
|
||||||
const wcstring name;
|
const wcstring name;
|
||||||
|
|
||||||
/** New items. */
|
/** New items. */
|
||||||
std::vector<history_item_t> new_items;
|
std::vector<history_item_t> new_items;
|
||||||
|
|
||||||
/** Deleted item contents. */
|
/** Deleted item contents. */
|
||||||
std::set<wcstring> deleted_items;
|
std::set<wcstring> deleted_items;
|
||||||
|
|
||||||
/** How many items we've added without saving */
|
/** How many items we've added without saving */
|
||||||
size_t unsaved_item_count;
|
size_t unsaved_item_count;
|
||||||
|
|
||||||
/** The mmaped region for the history file */
|
/** The mmaped region for the history file */
|
||||||
const char *mmap_start;
|
const char *mmap_start;
|
||||||
|
|
||||||
/** The size of the mmap'd region */
|
/** The size of the mmap'd region */
|
||||||
size_t mmap_length;
|
size_t mmap_length;
|
||||||
|
|
||||||
/** The type of file we mmap'd */
|
/** The type of file we mmap'd */
|
||||||
history_file_type_t mmap_type;
|
history_file_type_t mmap_type;
|
||||||
|
@ -115,8 +115,8 @@ private:
|
||||||
/** Timestamp of when this history was created */
|
/** Timestamp of when this history was created */
|
||||||
const time_t birth_timestamp;
|
const time_t birth_timestamp;
|
||||||
|
|
||||||
/** Timestamp of last save */
|
/** Timestamp of last save */
|
||||||
time_t save_timestamp;
|
time_t save_timestamp;
|
||||||
|
|
||||||
void populate_from_mmap(void);
|
void populate_from_mmap(void);
|
||||||
|
|
||||||
|
|
658
input.cpp
658
input.cpp
|
@ -74,8 +74,8 @@
|
||||||
*/
|
*/
|
||||||
struct input_mapping_t
|
struct input_mapping_t
|
||||||
{
|
{
|
||||||
wcstring seq; /**< Character sequence which generates this event */
|
wcstring seq; /**< Character sequence which generates this event */
|
||||||
wcstring command; /**< command that should be evaluated by this mapping */
|
wcstring command; /**< command that should be evaluated by this mapping */
|
||||||
|
|
||||||
|
|
||||||
input_mapping_t(const wcstring &s, const wcstring &c) : seq(s), command(c) {}
|
input_mapping_t(const wcstring &s, const wcstring &c) : seq(s), command(c) {}
|
||||||
|
@ -86,8 +86,8 @@ struct input_mapping_t
|
||||||
*/
|
*/
|
||||||
struct terminfo_mapping_t
|
struct terminfo_mapping_t
|
||||||
{
|
{
|
||||||
const wchar_t *name; /**< Name of key */
|
const wchar_t *name; /**< Name of key */
|
||||||
const char *seq; /**< Character sequence generated on keypress. Constant string. */
|
const char *seq; /**< Character sequence generated on keypress. Constant string. */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,43 +97,43 @@ struct terminfo_mapping_t
|
||||||
*/
|
*/
|
||||||
static const wchar_t * const name_arr[] =
|
static const wchar_t * const name_arr[] =
|
||||||
{
|
{
|
||||||
L"beginning-of-line",
|
L"beginning-of-line",
|
||||||
L"end-of-line",
|
L"end-of-line",
|
||||||
L"forward-char",
|
L"forward-char",
|
||||||
L"backward-char",
|
L"backward-char",
|
||||||
L"forward-word",
|
L"forward-word",
|
||||||
L"backward-word",
|
L"backward-word",
|
||||||
L"history-search-backward",
|
L"history-search-backward",
|
||||||
L"history-search-forward",
|
L"history-search-forward",
|
||||||
L"delete-char",
|
L"delete-char",
|
||||||
L"backward-delete-char",
|
L"backward-delete-char",
|
||||||
L"kill-line",
|
L"kill-line",
|
||||||
L"yank",
|
L"yank",
|
||||||
L"yank-pop",
|
L"yank-pop",
|
||||||
L"complete",
|
L"complete",
|
||||||
L"beginning-of-history",
|
L"beginning-of-history",
|
||||||
L"end-of-history",
|
L"end-of-history",
|
||||||
L"backward-kill-line",
|
L"backward-kill-line",
|
||||||
L"kill-whole-line",
|
L"kill-whole-line",
|
||||||
L"kill-word",
|
L"kill-word",
|
||||||
L"backward-kill-word",
|
L"backward-kill-word",
|
||||||
L"dump-functions",
|
L"dump-functions",
|
||||||
L"history-token-search-backward",
|
L"history-token-search-backward",
|
||||||
L"history-token-search-forward",
|
L"history-token-search-forward",
|
||||||
L"self-insert",
|
L"self-insert",
|
||||||
L"null",
|
L"null",
|
||||||
L"eof",
|
L"eof",
|
||||||
L"vi-arg-digit",
|
L"vi-arg-digit",
|
||||||
L"execute",
|
L"execute",
|
||||||
L"beginning-of-buffer",
|
L"beginning-of-buffer",
|
||||||
L"end-of-buffer",
|
L"end-of-buffer",
|
||||||
L"repaint",
|
L"repaint",
|
||||||
L"up-line",
|
L"up-line",
|
||||||
L"down-line",
|
L"down-line",
|
||||||
L"suppress-autosuggestion",
|
L"suppress-autosuggestion",
|
||||||
L"accept-autosuggestion"
|
L"accept-autosuggestion"
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Description of each supported input function
|
Description of each supported input function
|
||||||
|
@ -141,38 +141,38 @@ static const wchar_t * const name_arr[] =
|
||||||
/*
|
/*
|
||||||
static const wchar_t *desc_arr[] =
|
static const wchar_t *desc_arr[] =
|
||||||
{
|
{
|
||||||
L"Move to beginning of line",
|
L"Move to beginning of line",
|
||||||
L"Move to end of line",
|
L"Move to end of line",
|
||||||
L"Move forward one character",
|
L"Move forward one character",
|
||||||
L"Move backward one character",
|
L"Move backward one character",
|
||||||
L"Move forward one word",
|
L"Move forward one word",
|
||||||
L"Move backward one word",
|
L"Move backward one word",
|
||||||
L"Search backward through list of previous commands",
|
L"Search backward through list of previous commands",
|
||||||
L"Search forward through list of previous commands",
|
L"Search forward through list of previous commands",
|
||||||
L"Delete one character forward",
|
L"Delete one character forward",
|
||||||
L"Delete one character backward",
|
L"Delete one character backward",
|
||||||
L"Move contents from cursor to end of line to killring",
|
L"Move contents from cursor to end of line to killring",
|
||||||
L"Paste contents of killring",
|
L"Paste contents of killring",
|
||||||
L"Rotate to previous killring entry",
|
L"Rotate to previous killring entry",
|
||||||
L"Guess the rest of the next input token",
|
L"Guess the rest of the next input token",
|
||||||
L"Move to first item of history",
|
L"Move to first item of history",
|
||||||
L"Move to last item of history",
|
L"Move to last item of history",
|
||||||
L"Clear current line",
|
L"Clear current line",
|
||||||
L"Move contents from beginning of line to cursor to killring",
|
L"Move contents from beginning of line to cursor to killring",
|
||||||
L"Move entire line to killring",
|
L"Move entire line to killring",
|
||||||
L"Move next word to killring",
|
L"Move next word to killring",
|
||||||
L"Move previous word to killring",
|
L"Move previous word to killring",
|
||||||
L"Write out key bindings",
|
L"Write out key bindings",
|
||||||
L"Clear entire screen",
|
L"Clear entire screen",
|
||||||
L"Quit the running program",
|
L"Quit the running program",
|
||||||
L"Search backward through list of previous commands for matching token",
|
L"Search backward through list of previous commands for matching token",
|
||||||
L"Search forward through list of previous commands for matching token",
|
L"Search forward through list of previous commands for matching token",
|
||||||
L"Insert the pressed key",
|
L"Insert the pressed key",
|
||||||
L"Do nothing",
|
L"Do nothing",
|
||||||
L"End of file",
|
L"End of file",
|
||||||
L"Repeat command"
|
L"Repeat command"
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,43 +180,43 @@ static const wchar_t *desc_arr[] =
|
||||||
*/
|
*/
|
||||||
static const wchar_t code_arr[] =
|
static const wchar_t code_arr[] =
|
||||||
{
|
{
|
||||||
R_BEGINNING_OF_LINE,
|
R_BEGINNING_OF_LINE,
|
||||||
R_END_OF_LINE,
|
R_END_OF_LINE,
|
||||||
R_FORWARD_CHAR,
|
R_FORWARD_CHAR,
|
||||||
R_BACKWARD_CHAR,
|
R_BACKWARD_CHAR,
|
||||||
R_FORWARD_WORD,
|
R_FORWARD_WORD,
|
||||||
R_BACKWARD_WORD,
|
R_BACKWARD_WORD,
|
||||||
R_HISTORY_SEARCH_BACKWARD,
|
R_HISTORY_SEARCH_BACKWARD,
|
||||||
R_HISTORY_SEARCH_FORWARD,
|
R_HISTORY_SEARCH_FORWARD,
|
||||||
R_DELETE_CHAR,
|
R_DELETE_CHAR,
|
||||||
R_BACKWARD_DELETE_CHAR,
|
R_BACKWARD_DELETE_CHAR,
|
||||||
R_KILL_LINE,
|
R_KILL_LINE,
|
||||||
R_YANK,
|
R_YANK,
|
||||||
R_YANK_POP,
|
R_YANK_POP,
|
||||||
R_COMPLETE,
|
R_COMPLETE,
|
||||||
R_BEGINNING_OF_HISTORY,
|
R_BEGINNING_OF_HISTORY,
|
||||||
R_END_OF_HISTORY,
|
R_END_OF_HISTORY,
|
||||||
R_BACKWARD_KILL_LINE,
|
R_BACKWARD_KILL_LINE,
|
||||||
R_KILL_WHOLE_LINE,
|
R_KILL_WHOLE_LINE,
|
||||||
R_KILL_WORD,
|
R_KILL_WORD,
|
||||||
R_BACKWARD_KILL_WORD,
|
R_BACKWARD_KILL_WORD,
|
||||||
R_DUMP_FUNCTIONS,
|
R_DUMP_FUNCTIONS,
|
||||||
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
||||||
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
||||||
R_SELF_INSERT,
|
R_SELF_INSERT,
|
||||||
R_NULL,
|
R_NULL,
|
||||||
R_EOF,
|
R_EOF,
|
||||||
R_VI_ARG_DIGIT,
|
R_VI_ARG_DIGIT,
|
||||||
R_EXECUTE,
|
R_EXECUTE,
|
||||||
R_BEGINNING_OF_BUFFER,
|
R_BEGINNING_OF_BUFFER,
|
||||||
R_END_OF_BUFFER,
|
R_END_OF_BUFFER,
|
||||||
R_REPAINT,
|
R_REPAINT,
|
||||||
R_UP_LINE,
|
R_UP_LINE,
|
||||||
R_DOWN_LINE,
|
R_DOWN_LINE,
|
||||||
R_SUPPRESS_AUTOSUGGESTION,
|
R_SUPPRESS_AUTOSUGGESTION,
|
||||||
R_ACCEPT_AUTOSUGGESTION
|
R_ACCEPT_AUTOSUGGESTION
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/** Mappings for the current input mode */
|
/** Mappings for the current input mode */
|
||||||
static std::vector<input_mapping_t> mapping_list;
|
static std::vector<input_mapping_t> mapping_list;
|
||||||
|
@ -249,24 +249,24 @@ static void input_terminfo_init();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void input_mapping_add( const wchar_t *sequence,
|
void input_mapping_add( const wchar_t *sequence,
|
||||||
const wchar_t *command )
|
const wchar_t *command )
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
CHECK( sequence, );
|
CHECK( sequence, );
|
||||||
CHECK( command, );
|
CHECK( command, );
|
||||||
|
|
||||||
// debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) );
|
// debug( 0, L"Add mapping from %ls to %ls", escape(sequence, 1), escape(command, 1 ) );
|
||||||
|
|
||||||
|
|
||||||
for( i=0; i<mapping_list.size(); i++ )
|
for( i=0; i<mapping_list.size(); i++ )
|
||||||
{
|
{
|
||||||
input_mapping_t &m = mapping_list.at(i);
|
input_mapping_t &m = mapping_list.at(i);
|
||||||
if( m.seq == sequence )
|
if( m.seq == sequence )
|
||||||
{
|
{
|
||||||
m.command = command;
|
m.command = command;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapping_list.push_back(input_mapping_t(sequence, command));
|
mapping_list.push_back(input_mapping_t(sequence, command));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,29 +276,29 @@ void input_mapping_add( const wchar_t *sequence,
|
||||||
*/
|
*/
|
||||||
static int interrupt_handler()
|
static int interrupt_handler()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Fire any pending events
|
Fire any pending events
|
||||||
*/
|
*/
|
||||||
event_fire( NULL );
|
event_fire( NULL );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reap stray processes, including printing exit status messages
|
Reap stray processes, including printing exit status messages
|
||||||
*/
|
*/
|
||||||
if( job_reap( 1 ) )
|
if( job_reap( 1 ) )
|
||||||
reader_repaint_needed();
|
reader_repaint_needed();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tell the reader an event occured
|
Tell the reader an event occured
|
||||||
*/
|
*/
|
||||||
if( reader_interrupted() )
|
if( reader_interrupted() )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Return 3, i.e. the character read by a Control-C.
|
Return 3, i.e. the character read by a Control-C.
|
||||||
*/
|
*/
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return R_NULL;
|
return R_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_fish_term256(void)
|
void update_fish_term256(void)
|
||||||
|
@ -329,54 +329,54 @@ void update_fish_term256(void)
|
||||||
|
|
||||||
int input_init()
|
int input_init()
|
||||||
{
|
{
|
||||||
if( is_init )
|
if( is_init )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
is_init = 1;
|
is_init = 1;
|
||||||
|
|
||||||
input_common_init( &interrupt_handler );
|
input_common_init( &interrupt_handler );
|
||||||
|
|
||||||
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
|
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
|
||||||
{
|
{
|
||||||
debug( 0, _( L"Could not set up terminal" ) );
|
debug( 0, _( L"Could not set up terminal" ) );
|
||||||
exit_without_destructors(1);
|
exit_without_destructors(1);
|
||||||
}
|
}
|
||||||
const env_var_t term = env_get_string( L"TERM" );
|
const env_var_t term = env_get_string( L"TERM" );
|
||||||
assert(! term.missing());
|
assert(! term.missing());
|
||||||
output_set_term( term.c_str() );
|
output_set_term( term.c_str() );
|
||||||
|
|
||||||
input_terminfo_init();
|
input_terminfo_init();
|
||||||
|
|
||||||
update_fish_term256();
|
update_fish_term256();
|
||||||
|
|
||||||
/* If we have no keybindings, add a few simple defaults */
|
/* If we have no keybindings, add a few simple defaults */
|
||||||
if( mapping_list.empty() )
|
if( mapping_list.empty() )
|
||||||
{
|
{
|
||||||
input_mapping_add( L"", L"self-insert" );
|
input_mapping_add( L"", L"self-insert" );
|
||||||
input_mapping_add( L"\n", L"execute" );
|
input_mapping_add( L"\n", L"execute" );
|
||||||
input_mapping_add( L"\t", L"complete" );
|
input_mapping_add( L"\t", L"complete" );
|
||||||
input_mapping_add( L"\x3", L"commandline \"\"" );
|
input_mapping_add( L"\x3", L"commandline \"\"" );
|
||||||
input_mapping_add( L"\x4", L"exit" );
|
input_mapping_add( L"\x4", L"exit" );
|
||||||
input_mapping_add( L"\x5", L"bind" );
|
input_mapping_add( L"\x5", L"bind" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_destroy()
|
void input_destroy()
|
||||||
{
|
{
|
||||||
if( !is_init )
|
if( !is_init )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
is_init=0;
|
is_init=0;
|
||||||
|
|
||||||
input_common_destroy();
|
input_common_destroy();
|
||||||
|
|
||||||
if( del_curterm( cur_term ) == ERR )
|
if( del_curterm( cur_term ) == ERR )
|
||||||
{
|
{
|
||||||
debug( 0, _(L"Error while closing terminfo") );
|
debug( 0, _(L"Error while closing terminfo") );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -384,50 +384,50 @@ void input_destroy()
|
||||||
*/
|
*/
|
||||||
static wint_t input_exec_binding( const input_mapping_t &m, const wcstring &seq )
|
static wint_t input_exec_binding( const input_mapping_t &m, const wcstring &seq )
|
||||||
{
|
{
|
||||||
wchar_t code = input_function_get_code( m.command );
|
wchar_t code = input_function_get_code( m.command );
|
||||||
if( code != -1 )
|
if( code != -1 )
|
||||||
{
|
{
|
||||||
switch( code )
|
switch( code )
|
||||||
{
|
{
|
||||||
|
|
||||||
case R_SELF_INSERT:
|
case R_SELF_INSERT:
|
||||||
{
|
{
|
||||||
return seq[0];
|
return seq[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This key sequence is bound to a command, which
|
This key sequence is bound to a command, which
|
||||||
is sent to the parser for evaluation.
|
is sent to the parser for evaluation.
|
||||||
*/
|
*/
|
||||||
int last_status = proc_get_last_status();
|
int last_status = proc_get_last_status();
|
||||||
|
|
||||||
parser_t::principal_parser().eval( m.command.c_str(), io_chain_t(), TOP );
|
parser_t::principal_parser().eval( m.command.c_str(), io_chain_t(), TOP );
|
||||||
|
|
||||||
proc_set_last_status( last_status );
|
proc_set_last_status( last_status );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We still need to return something to the caller, R_NULL
|
We still need to return something to the caller, R_NULL
|
||||||
tells the reader that no key press needs to be handled,
|
tells the reader that no key press needs to be handled,
|
||||||
and no repaint is needed.
|
and no repaint is needed.
|
||||||
|
|
||||||
Bindings that produce output should emit a R_REPAINT
|
Bindings that produce output should emit a R_REPAINT
|
||||||
function by calling 'commandline -f repaint' to tell
|
function by calling 'commandline -f repaint' to tell
|
||||||
fish that a repaint is in order.
|
fish that a repaint is in order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return R_NULL;
|
return R_NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,18 +437,18 @@ static wint_t input_exec_binding( const input_mapping_t &m, const wcstring &seq
|
||||||
*/
|
*/
|
||||||
static wint_t input_try_mapping( const input_mapping_t &m)
|
static wint_t input_try_mapping( const input_mapping_t &m)
|
||||||
{
|
{
|
||||||
wint_t c=0;
|
wint_t c=0;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if the actual function code of this mapping is on the stack
|
Check if the actual function code of this mapping is on the stack
|
||||||
*/
|
*/
|
||||||
c = input_common_readch( 0 );
|
c = input_common_readch( 0 );
|
||||||
if( c == input_function_get_code( m.command ) )
|
if( c == input_function_get_code( m.command ) )
|
||||||
{
|
{
|
||||||
return input_exec_binding( m, m.seq );
|
return input_exec_binding( m, m.seq );
|
||||||
}
|
}
|
||||||
input_unreadch( c );
|
input_unreadch( c );
|
||||||
|
|
||||||
const wchar_t *str = m.seq.c_str();
|
const wchar_t *str = m.seq.c_str();
|
||||||
for (j=0; str[j] != L'\0'; j++)
|
for (j=0; str[j] != L'\0'; j++)
|
||||||
|
@ -476,70 +476,70 @@ static wint_t input_try_mapping( const input_mapping_t &m)
|
||||||
input_unreadch( m.seq[k] );
|
input_unreadch( m.seq[k] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_unreadch( wint_t ch )
|
void input_unreadch( wint_t ch )
|
||||||
{
|
{
|
||||||
input_common_unreadch( ch );
|
input_common_unreadch( ch );
|
||||||
}
|
}
|
||||||
|
|
||||||
wint_t input_readch()
|
wint_t input_readch()
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
CHECK_BLOCK( R_NULL );
|
CHECK_BLOCK( R_NULL );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Clear the interrupted flag
|
Clear the interrupted flag
|
||||||
*/
|
*/
|
||||||
reader_interrupted();
|
reader_interrupted();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Search for sequence in mapping tables
|
Search for sequence in mapping tables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
const input_mapping_t *generic = 0;
|
const input_mapping_t *generic = 0;
|
||||||
for( i=0; i<mapping_list.size(); i++ )
|
for( i=0; i<mapping_list.size(); i++ )
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(i);
|
const input_mapping_t &m = mapping_list.at(i);
|
||||||
wint_t res = input_try_mapping( m );
|
wint_t res = input_try_mapping( m );
|
||||||
if( res )
|
if( res )
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
if( m.seq.length() == 0 )
|
if( m.seq.length() == 0 )
|
||||||
{
|
{
|
||||||
generic = &m;
|
generic = &m;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No matching exact mapping, try to find generic mapping.
|
No matching exact mapping, try to find generic mapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( generic )
|
if( generic )
|
||||||
{
|
{
|
||||||
wchar_t arr[2]=
|
wchar_t arr[2]=
|
||||||
{
|
{
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
arr[0] = input_common_readch(0);
|
arr[0] = input_common_readch(0);
|
||||||
|
|
||||||
return input_exec_binding( *generic, arr );
|
return input_exec_binding( *generic, arr );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
No action to take on specified character, ignore it
|
No action to take on specified character, ignore it
|
||||||
and move to next one.
|
and move to next one.
|
||||||
*/
|
*/
|
||||||
wchar_t c = input_common_readch( 0 );
|
wchar_t c = input_common_readch( 0 );
|
||||||
|
|
||||||
/* If it's closed, then just return */
|
/* If it's closed, then just return */
|
||||||
if (c == R_EOF)
|
if (c == R_EOF)
|
||||||
|
@ -551,13 +551,13 @@ wint_t input_readch()
|
||||||
|
|
||||||
void input_mapping_get_names( wcstring_list_t &lst )
|
void input_mapping_get_names( wcstring_list_t &lst )
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for( i=0; i<mapping_list.size(); i++ )
|
for( i=0; i<mapping_list.size(); i++ )
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(i);
|
const input_mapping_t &m = mapping_list.at(i);
|
||||||
lst.push_back(wcstring(m.seq));
|
lst.push_back(wcstring(m.seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,41 +565,41 @@ void input_mapping_get_names( wcstring_list_t &lst )
|
||||||
bool input_mapping_erase( const wchar_t *sequence )
|
bool input_mapping_erase( const wchar_t *sequence )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
size_t i, sz = mapping_list.size();
|
size_t i, sz = mapping_list.size();
|
||||||
|
|
||||||
for( i=0; i<sz; i++ )
|
for( i=0; i<sz; i++ )
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(i);
|
const input_mapping_t &m = mapping_list.at(i);
|
||||||
if( sequence == m.seq )
|
if( sequence == m.seq )
|
||||||
{
|
{
|
||||||
if( i != (sz-1 ) )
|
if( i != (sz-1 ) )
|
||||||
{
|
{
|
||||||
mapping_list[i] = mapping_list[sz-1];
|
mapping_list[i] = mapping_list[sz-1];
|
||||||
}
|
}
|
||||||
mapping_list.pop_back();
|
mapping_list.pop_back();
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool input_mapping_get( const wcstring &sequence, wcstring &cmd )
|
bool input_mapping_get( const wcstring &sequence, wcstring &cmd )
|
||||||
{
|
{
|
||||||
size_t i, sz = mapping_list.size();
|
size_t i, sz = mapping_list.size();
|
||||||
|
|
||||||
for( i=0; i<sz; i++ )
|
for( i=0; i<sz; i++ )
|
||||||
{
|
{
|
||||||
const input_mapping_t &m = mapping_list.at(i);
|
const input_mapping_t &m = mapping_list.at(i);
|
||||||
if( sequence == m.seq )
|
if( sequence == m.seq )
|
||||||
{
|
{
|
||||||
cmd = m.command;
|
cmd = m.command;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -655,11 +655,11 @@ static void input_terminfo_init()
|
||||||
TERMINFO_ADD(key_f19),
|
TERMINFO_ADD(key_f19),
|
||||||
TERMINFO_ADD(key_f20),
|
TERMINFO_ADD(key_f20),
|
||||||
/*
|
/*
|
||||||
I know of no keyboard with more than 20 function keys, so
|
I know of no keyboard with more than 20 function keys, so
|
||||||
adding the rest here makes very little sense, since it will
|
adding the rest here makes very little sense, since it will
|
||||||
take up a lot of room in any listings (like tab completions),
|
take up a lot of room in any listings (like tab completions),
|
||||||
but with no benefit.
|
but with no benefit.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
TERMINFO_ADD(key_f21),
|
TERMINFO_ADD(key_f21),
|
||||||
TERMINFO_ADD(key_f22),
|
TERMINFO_ADD(key_f22),
|
||||||
|
@ -774,47 +774,47 @@ const wchar_t *input_terminfo_get_sequence( const wchar_t *name )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
const char *res = 0;
|
const char *res = 0;
|
||||||
static wcstring buff;
|
static wcstring buff;
|
||||||
int err = ENOENT;
|
int err = ENOENT;
|
||||||
|
|
||||||
CHECK( name, 0 );
|
CHECK( name, 0 );
|
||||||
input_init();
|
input_init();
|
||||||
|
|
||||||
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
||||||
{
|
{
|
||||||
const terminfo_mapping_t &m = terminfo_mappings.at(i);
|
const terminfo_mapping_t &m = terminfo_mappings.at(i);
|
||||||
if( !wcscmp( name, m.name ) )
|
if( !wcscmp( name, m.name ) )
|
||||||
{
|
{
|
||||||
res = m.seq;
|
res = m.seq;
|
||||||
err = EILSEQ;
|
err = EILSEQ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !res )
|
if( !res )
|
||||||
{
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = format_string(L"%s", res);
|
buff = format_string(L"%s", res);
|
||||||
return buff.c_str();
|
return buff.c_str();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool input_terminfo_get_name( const wcstring &seq, wcstring &name )
|
bool input_terminfo_get_name( const wcstring &seq, wcstring &name )
|
||||||
{
|
{
|
||||||
input_init();
|
input_init();
|
||||||
|
|
||||||
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
||||||
{
|
{
|
||||||
terminfo_mapping_t &m = terminfo_mappings.at(i);
|
terminfo_mapping_t &m = terminfo_mappings.at(i);
|
||||||
|
|
||||||
if( !m.seq )
|
if( !m.seq )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wcstring map_buf = format_string(L"%s", m.seq);
|
const wcstring map_buf = format_string(L"%s", m.seq);
|
||||||
if (map_buf == seq) {
|
if (map_buf == seq) {
|
||||||
|
@ -823,7 +823,7 @@ bool input_terminfo_get_name( const wcstring &seq, wcstring &name )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring_list_t input_terminfo_get_names( bool skip_null )
|
wcstring_list_t input_terminfo_get_names( bool skip_null )
|
||||||
|
@ -831,18 +831,18 @@ wcstring_list_t input_terminfo_get_names( bool skip_null )
|
||||||
wcstring_list_t result;
|
wcstring_list_t result;
|
||||||
result.reserve(terminfo_mappings.size());
|
result.reserve(terminfo_mappings.size());
|
||||||
|
|
||||||
input_init();
|
input_init();
|
||||||
|
|
||||||
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
for( size_t i=0; i<terminfo_mappings.size(); i++ )
|
||||||
{
|
{
|
||||||
terminfo_mapping_t &m = terminfo_mappings.at(i);
|
terminfo_mapping_t &m = terminfo_mappings.at(i);
|
||||||
|
|
||||||
if( skip_null && !m.seq )
|
if( skip_null && !m.seq )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.push_back(wcstring(m.name));
|
result.push_back(wcstring(m.name));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,13 +855,13 @@ wcstring_list_t input_function_get_names( void )
|
||||||
wchar_t input_function_get_code( const wcstring &name )
|
wchar_t input_function_get_code( const wcstring &name )
|
||||||
{
|
{
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for( i = 0; i<(sizeof( code_arr )/sizeof(wchar_t)) ; i++ )
|
for( i = 0; i<(sizeof( code_arr )/sizeof(wchar_t)) ; i++ )
|
||||||
{
|
{
|
||||||
if( name == name_arr[i] )
|
if( name == name_arr[i] )
|
||||||
{
|
{
|
||||||
return code_arr[i];
|
return code_arr[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
68
input.h
68
input.h
|
@ -17,40 +17,40 @@ inputrc information for key bindings.
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */
|
R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */
|
||||||
R_END_OF_LINE,
|
R_END_OF_LINE,
|
||||||
R_FORWARD_CHAR,
|
R_FORWARD_CHAR,
|
||||||
R_BACKWARD_CHAR,
|
R_BACKWARD_CHAR,
|
||||||
R_FORWARD_WORD,
|
R_FORWARD_WORD,
|
||||||
R_BACKWARD_WORD,
|
R_BACKWARD_WORD,
|
||||||
R_HISTORY_SEARCH_BACKWARD,
|
R_HISTORY_SEARCH_BACKWARD,
|
||||||
R_HISTORY_SEARCH_FORWARD,
|
R_HISTORY_SEARCH_FORWARD,
|
||||||
R_DELETE_CHAR,
|
R_DELETE_CHAR,
|
||||||
R_BACKWARD_DELETE_CHAR,
|
R_BACKWARD_DELETE_CHAR,
|
||||||
R_KILL_LINE,
|
R_KILL_LINE,
|
||||||
R_YANK,
|
R_YANK,
|
||||||
R_YANK_POP,
|
R_YANK_POP,
|
||||||
R_COMPLETE,
|
R_COMPLETE,
|
||||||
R_BEGINNING_OF_HISTORY,
|
R_BEGINNING_OF_HISTORY,
|
||||||
R_END_OF_HISTORY,
|
R_END_OF_HISTORY,
|
||||||
R_BACKWARD_KILL_LINE,
|
R_BACKWARD_KILL_LINE,
|
||||||
R_KILL_WHOLE_LINE,
|
R_KILL_WHOLE_LINE,
|
||||||
R_KILL_WORD,
|
R_KILL_WORD,
|
||||||
R_BACKWARD_KILL_WORD,
|
R_BACKWARD_KILL_WORD,
|
||||||
R_DUMP_FUNCTIONS,
|
R_DUMP_FUNCTIONS,
|
||||||
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
R_HISTORY_TOKEN_SEARCH_BACKWARD,
|
||||||
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
R_HISTORY_TOKEN_SEARCH_FORWARD,
|
||||||
R_SELF_INSERT,
|
R_SELF_INSERT,
|
||||||
R_VI_ARG_DIGIT,
|
R_VI_ARG_DIGIT,
|
||||||
R_VI_DELETE_TO,
|
R_VI_DELETE_TO,
|
||||||
R_EXECUTE,
|
R_EXECUTE,
|
||||||
R_BEGINNING_OF_BUFFER,
|
R_BEGINNING_OF_BUFFER,
|
||||||
R_END_OF_BUFFER,
|
R_END_OF_BUFFER,
|
||||||
R_REPAINT,
|
R_REPAINT,
|
||||||
R_UP_LINE,
|
R_UP_LINE,
|
||||||
R_DOWN_LINE,
|
R_DOWN_LINE,
|
||||||
R_SUPPRESS_AUTOSUGGESTION,
|
R_SUPPRESS_AUTOSUGGESTION,
|
||||||
R_ACCEPT_AUTOSUGGESTION
|
R_ACCEPT_AUTOSUGGESTION
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
268
input_common.cpp
268
input_common.cpp
|
@ -53,7 +53,7 @@ static void (*poll_handler)();
|
||||||
|
|
||||||
void input_common_init( int (*ih)() )
|
void input_common_init( int (*ih)() )
|
||||||
{
|
{
|
||||||
interrupt_handler = ih;
|
interrupt_handler = ih;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_common_set_poll_callback(void (*handler)(void))
|
void input_common_set_poll_callback(void (*handler)(void))
|
||||||
|
@ -73,69 +73,69 @@ void input_common_destroy()
|
||||||
static wint_t readb()
|
static wint_t readb()
|
||||||
{
|
{
|
||||||
/* do_loop must be set on every path through the loop; leaving it uninitialized allows the static analyzer to assist in catching mistakes. */
|
/* do_loop must be set on every path through the loop; leaving it uninitialized allows the static analyzer to assist in catching mistakes. */
|
||||||
unsigned char arr[1];
|
unsigned char arr[1];
|
||||||
bool do_loop;
|
bool do_loop;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* Invoke any poll handler */
|
/* Invoke any poll handler */
|
||||||
if (poll_handler)
|
if (poll_handler)
|
||||||
poll_handler();
|
poll_handler();
|
||||||
|
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
int fd_max=0;
|
int fd_max=0;
|
||||||
int ioport = iothread_port();
|
int ioport = iothread_port();
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
FD_ZERO( &fdset );
|
FD_ZERO( &fdset );
|
||||||
FD_SET( 0, &fdset );
|
FD_SET( 0, &fdset );
|
||||||
if( env_universal_server.fd > 0 )
|
if( env_universal_server.fd > 0 )
|
||||||
{
|
{
|
||||||
FD_SET( env_universal_server.fd, &fdset );
|
FD_SET( env_universal_server.fd, &fdset );
|
||||||
if (fd_max < env_universal_server.fd) fd_max = env_universal_server.fd;
|
if (fd_max < env_universal_server.fd) fd_max = env_universal_server.fd;
|
||||||
}
|
}
|
||||||
if (ioport > 0) {
|
if (ioport > 0) {
|
||||||
FD_SET( ioport, &fdset );
|
FD_SET( ioport, &fdset );
|
||||||
if (fd_max < ioport) fd_max = ioport;
|
if (fd_max < ioport) fd_max = ioport;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = select( fd_max + 1, &fdset, 0, 0, 0 );
|
res = select( fd_max + 1, &fdset, 0, 0, 0 );
|
||||||
if( res==-1 )
|
if( res==-1 )
|
||||||
{
|
{
|
||||||
switch( errno )
|
switch( errno )
|
||||||
{
|
{
|
||||||
case EINTR:
|
case EINTR:
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
{
|
{
|
||||||
if( interrupt_handler )
|
if( interrupt_handler )
|
||||||
{
|
{
|
||||||
int res = interrupt_handler();
|
int res = interrupt_handler();
|
||||||
if( res )
|
if( res )
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if( lookahead_count )
|
if( lookahead_count )
|
||||||
{
|
{
|
||||||
return lookahead_arr[--lookahead_count];
|
return lookahead_arr[--lookahead_count];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
do_loop = true;
|
do_loop = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The terminal has been closed. Save and exit.
|
The terminal has been closed. Save and exit.
|
||||||
*/
|
*/
|
||||||
return R_EOF;
|
return R_EOF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Assume we loop unless we see a character in stdin */
|
/* Assume we loop unless we see a character in stdin */
|
||||||
do_loop = true;
|
do_loop = true;
|
||||||
|
|
||||||
|
@ -149,116 +149,116 @@ static wint_t readb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ioport > 0 && FD_ISSET(ioport, &fdset))
|
if ( ioport > 0 && FD_ISSET(ioport, &fdset))
|
||||||
{
|
{
|
||||||
iothread_service_completion();
|
iothread_service_completion();
|
||||||
if( lookahead_count )
|
if( lookahead_count )
|
||||||
{
|
{
|
||||||
return lookahead_arr[--lookahead_count];
|
return lookahead_arr[--lookahead_count];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( FD_ISSET( STDIN_FILENO, &fdset ) )
|
if( FD_ISSET( STDIN_FILENO, &fdset ) )
|
||||||
{
|
{
|
||||||
if( read_blocked( 0, arr, 1 ) != 1 )
|
if( read_blocked( 0, arr, 1 ) != 1 )
|
||||||
{
|
{
|
||||||
/* The teminal has been closed. Save and exit. */
|
/* The teminal has been closed. Save and exit. */
|
||||||
return R_EOF;
|
return R_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We read from stdin, so don't loop */
|
/* We read from stdin, so don't loop */
|
||||||
do_loop = false;
|
do_loop = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while( do_loop );
|
while( do_loop );
|
||||||
|
|
||||||
return arr[0];
|
return arr[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t input_common_readch( int timed )
|
wchar_t input_common_readch( int timed )
|
||||||
{
|
{
|
||||||
if( lookahead_count == 0 )
|
if( lookahead_count == 0 )
|
||||||
{
|
{
|
||||||
if( timed )
|
if( timed )
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tm=
|
struct timeval tm=
|
||||||
{
|
{
|
||||||
0,
|
0,
|
||||||
1000 * WAIT_ON_ESCAPE
|
1000 * WAIT_ON_ESCAPE
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
FD_ZERO( &fds );
|
FD_ZERO( &fds );
|
||||||
FD_SET( 0, &fds );
|
FD_SET( 0, &fds );
|
||||||
count = select(1, &fds, 0, 0, &tm);
|
count = select(1, &fds, 0, 0, &tm);
|
||||||
|
|
||||||
switch( count )
|
switch( count )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return WEOF;
|
return WEOF;
|
||||||
|
|
||||||
case -1:
|
case -1:
|
||||||
return WEOF;
|
return WEOF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t res;
|
wchar_t res;
|
||||||
static mbstate_t state;
|
static mbstate_t state;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
wint_t b = readb();
|
wint_t b = readb();
|
||||||
char bb;
|
char bb;
|
||||||
|
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
||||||
if( (b >= R_NULL) && (b < R_NULL + 1000) )
|
if( (b >= R_NULL) && (b < R_NULL + 1000) )
|
||||||
return b;
|
return b;
|
||||||
|
|
||||||
bb=b;
|
bb=b;
|
||||||
|
|
||||||
sz = mbrtowc( &res, &bb, 1, &state );
|
sz = mbrtowc( &res, &bb, 1, &state );
|
||||||
|
|
||||||
switch( sz )
|
switch( sz )
|
||||||
{
|
{
|
||||||
case (size_t)(-1):
|
case (size_t)(-1):
|
||||||
memset (&state, '\0', sizeof (state));
|
memset (&state, '\0', sizeof (state));
|
||||||
debug( 2, L"Illegal input" );
|
debug( 2, L"Illegal input" );
|
||||||
return R_NULL;
|
return R_NULL;
|
||||||
case (size_t)(-2):
|
case (size_t)(-2):
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( !timed )
|
if( !timed )
|
||||||
{
|
{
|
||||||
while( (lookahead_count >= 0) && (lookahead_arr[lookahead_count-1] == WEOF) )
|
while( (lookahead_count >= 0) && (lookahead_arr[lookahead_count-1] == WEOF) )
|
||||||
lookahead_count--;
|
lookahead_count--;
|
||||||
if( lookahead_count == 0 )
|
if( lookahead_count == 0 )
|
||||||
return input_common_readch(0);
|
return input_common_readch(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lookahead_arr[--lookahead_count];
|
return lookahead_arr[--lookahead_count];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void input_common_unreadch( wint_t ch )
|
void input_common_unreadch( wint_t ch )
|
||||||
{
|
{
|
||||||
lookahead_arr[lookahead_count++] = ch;
|
lookahead_arr[lookahead_count++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,15 +15,15 @@ Header file for the low level input library
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
R_NULL is sometimes returned by the input when a character was
|
R_NULL is sometimes returned by the input when a character was
|
||||||
requested but none could be delivered, or when an exception
|
requested but none could be delivered, or when an exception
|
||||||
happened.
|
happened.
|
||||||
*/
|
*/
|
||||||
R_NULL = INPUT_COMMON_RESERVED,
|
R_NULL = INPUT_COMMON_RESERVED,
|
||||||
R_EOF
|
R_EOF
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Init the library
|
Init the library
|
||||||
|
|
10
intern.cpp
10
intern.cpp
|
@ -45,10 +45,10 @@ static pthread_mutex_t intern_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
|
static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
|
||||||
{
|
{
|
||||||
if( !in )
|
if( !in )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// debug( 0, L"intern %ls", in );
|
// debug( 0, L"intern %ls", in );
|
||||||
scoped_lock lock(intern_lock);
|
scoped_lock lock(intern_lock);
|
||||||
const wchar_t *result;
|
const wchar_t *result;
|
||||||
|
|
||||||
|
@ -74,11 +74,11 @@ static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
|
||||||
|
|
||||||
const wchar_t *intern( const wchar_t *in )
|
const wchar_t *intern( const wchar_t *in )
|
||||||
{
|
{
|
||||||
return intern_with_dup(in, true);
|
return intern_with_dup(in, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const wchar_t *intern_static( const wchar_t *in )
|
const wchar_t *intern_static( const wchar_t *in )
|
||||||
{
|
{
|
||||||
return intern_with_dup(in, false);
|
return intern_with_dup(in, false);
|
||||||
}
|
}
|
||||||
|
|
152
io.cpp
152
io.cpp
|
@ -53,76 +53,76 @@ Utilities for io redirection.
|
||||||
|
|
||||||
void io_buffer_read( io_data_t *d )
|
void io_buffer_read( io_data_t *d )
|
||||||
{
|
{
|
||||||
exec_close(d->param1.pipe_fd[1] );
|
exec_close(d->param1.pipe_fd[1] );
|
||||||
|
|
||||||
if( d->io_mode == IO_BUFFER )
|
if( d->io_mode == IO_BUFFER )
|
||||||
{
|
{
|
||||||
/* if( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
|
/* if( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
|
||||||
{
|
{
|
||||||
wperror( L"fcntl" );
|
wperror( L"fcntl" );
|
||||||
return;
|
return;
|
||||||
} */
|
} */
|
||||||
debug( 4, L"io_buffer_read: blocking read on fd %d", d->param1.pipe_fd[0] );
|
debug( 4, L"io_buffer_read: blocking read on fd %d", d->param1.pipe_fd[0] );
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
char b[4096];
|
char b[4096];
|
||||||
long l;
|
long l;
|
||||||
l=read_blocked( d->param1.pipe_fd[0], b, 4096 );
|
l=read_blocked( d->param1.pipe_fd[0], b, 4096 );
|
||||||
if( l==0 )
|
if( l==0 )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if( l<0 )
|
else if( l<0 )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
exec_read_io_buffer is only called on jobs that have
|
exec_read_io_buffer is only called on jobs that have
|
||||||
exited, and will therefore never block. But a broken
|
exited, and will therefore never block. But a broken
|
||||||
pipe seems to cause some flags to reset, causing the
|
pipe seems to cause some flags to reset, causing the
|
||||||
EOF flag to not be set. Therefore, EAGAIN is ignored
|
EOF flag to not be set. Therefore, EAGAIN is ignored
|
||||||
and we exit anyway.
|
and we exit anyway.
|
||||||
*/
|
*/
|
||||||
if( errno != EAGAIN )
|
if( errno != EAGAIN )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug( 1,
|
||||||
_(L"An error occured while reading output from code block on file descriptor %d"),
|
_(L"An error occured while reading output from code block on file descriptor %d"),
|
||||||
d->param1.pipe_fd[0] );
|
d->param1.pipe_fd[0] );
|
||||||
wperror( L"io_buffer_read" );
|
wperror( L"io_buffer_read" );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d->out_buffer_append( b, l );
|
d->out_buffer_append( b, l );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
io_data_t *io_buffer_create( bool is_input )
|
io_data_t *io_buffer_create( bool is_input )
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
io_data_t *buffer_redirect = new io_data_t;
|
io_data_t *buffer_redirect = new io_data_t;
|
||||||
buffer_redirect->out_buffer_create();
|
buffer_redirect->out_buffer_create();
|
||||||
buffer_redirect->io_mode = IO_BUFFER;
|
buffer_redirect->io_mode = IO_BUFFER;
|
||||||
buffer_redirect->is_input = is_input ? true : false;
|
buffer_redirect->is_input = is_input ? true : false;
|
||||||
buffer_redirect->fd=is_input?0:1;
|
buffer_redirect->fd=is_input?0:1;
|
||||||
|
|
||||||
if( exec_pipe( buffer_redirect->param1.pipe_fd ) == -1 )
|
if( exec_pipe( buffer_redirect->param1.pipe_fd ) == -1 )
|
||||||
{
|
{
|
||||||
debug( 1, PIPE_ERROR );
|
debug( 1, PIPE_ERROR );
|
||||||
wperror (L"pipe");
|
wperror (L"pipe");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if( fcntl( buffer_redirect->param1.pipe_fd[0],
|
else if( fcntl( buffer_redirect->param1.pipe_fd[0],
|
||||||
F_SETFL,
|
F_SETFL,
|
||||||
O_NONBLOCK ) )
|
O_NONBLOCK ) )
|
||||||
{
|
{
|
||||||
debug( 1, PIPE_ERROR );
|
debug( 1, PIPE_ERROR );
|
||||||
wperror( L"fcntl" );
|
wperror( L"fcntl" );
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! success)
|
if (! success)
|
||||||
{
|
{
|
||||||
|
@ -130,28 +130,28 @@ io_data_t *io_buffer_create( bool is_input )
|
||||||
buffer_redirect = NULL;
|
buffer_redirect = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer_redirect;
|
return buffer_redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void io_buffer_destroy( io_data_t *io_buffer )
|
void io_buffer_destroy( io_data_t *io_buffer )
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If this is an input buffer, then io_read_buffer will not have
|
If this is an input buffer, then io_read_buffer will not have
|
||||||
been called, and we need to close the output fd as well.
|
been called, and we need to close the output fd as well.
|
||||||
*/
|
*/
|
||||||
if( io_buffer->is_input )
|
if( io_buffer->is_input )
|
||||||
{
|
{
|
||||||
exec_close(io_buffer->param1.pipe_fd[1] );
|
exec_close(io_buffer->param1.pipe_fd[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_close( io_buffer->param1.pipe_fd[0] );
|
exec_close( io_buffer->param1.pipe_fd[0] );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Dont free fd for writing. This should already be free'd before
|
Dont free fd for writing. This should already be free'd before
|
||||||
calling exec_read_io_buffer on the buffer
|
calling exec_read_io_buffer on the buffer
|
||||||
*/
|
*/
|
||||||
delete io_buffer;
|
delete io_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void io_chain_t::remove(const io_data_t *element)
|
void io_chain_t::remove(const io_data_t *element)
|
||||||
|
|
50
io.h
50
io.h
|
@ -10,7 +10,7 @@ using std::tr1::shared_ptr;
|
||||||
*/
|
*/
|
||||||
enum io_mode
|
enum io_mode
|
||||||
{
|
{
|
||||||
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
|
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Represents an FD redirection */
|
/** Represents an FD redirection */
|
||||||
|
@ -24,31 +24,31 @@ private:
|
||||||
void operator=(const io_data_t &rhs);
|
void operator=(const io_data_t &rhs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Type of redirect */
|
/** Type of redirect */
|
||||||
int io_mode;
|
int io_mode;
|
||||||
/** FD to redirect */
|
/** FD to redirect */
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Type-specific parameter for redirection
|
Type-specific parameter for redirection
|
||||||
*/
|
*/
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
/** Fds for IO_PIPE and for IO_BUFFER */
|
/** Fds for IO_PIPE and for IO_BUFFER */
|
||||||
int pipe_fd[2];
|
int pipe_fd[2];
|
||||||
/** fd to redirect specified fd to, for IO_FD */
|
/** fd to redirect specified fd to, for IO_FD */
|
||||||
int old_fd;
|
int old_fd;
|
||||||
} param1;
|
} param1;
|
||||||
|
|
||||||
|
|
||||||
/** Second type-specific paramter for redirection */
|
/** Second type-specific paramter for redirection */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
/** file creation flags to send to open for IO_FILE */
|
/** file creation flags to send to open for IO_FILE */
|
||||||
int flags;
|
int flags;
|
||||||
/** Whether to close old_fd for IO_FD */
|
/** Whether to close old_fd for IO_FD */
|
||||||
int close_old;
|
int close_old;
|
||||||
} param2;
|
} param2;
|
||||||
|
|
||||||
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
|
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
|
||||||
const char *filename_cstr;
|
const char *filename_cstr;
|
||||||
|
@ -87,8 +87,8 @@ public:
|
||||||
return out_buffer->size();
|
return out_buffer->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set to true if this is an input io redirection */
|
/** Set to true if this is an input io redirection */
|
||||||
bool is_input;
|
bool is_input;
|
||||||
|
|
||||||
io_data_t() :
|
io_data_t() :
|
||||||
out_buffer(),
|
out_buffer(),
|
||||||
|
|
158
iothread.cpp
158
iothread.cpp
|
@ -27,24 +27,24 @@ static int s_active_thread_count;
|
||||||
typedef unsigned char ThreadIndex_t;
|
typedef unsigned char ThreadIndex_t;
|
||||||
|
|
||||||
static struct WorkerThread_t {
|
static struct WorkerThread_t {
|
||||||
ThreadIndex_t idx;
|
ThreadIndex_t idx;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
} threads[IO_MAX_THREADS];
|
} threads[IO_MAX_THREADS];
|
||||||
|
|
||||||
struct ThreadedRequest_t {
|
struct ThreadedRequest_t {
|
||||||
int sequenceNumber;
|
int sequenceNumber;
|
||||||
|
|
||||||
int (*handler)(void *);
|
int (*handler)(void *);
|
||||||
void (*completionCallback)(void *, int);
|
void (*completionCallback)(void *, int);
|
||||||
void *context;
|
void *context;
|
||||||
int handlerResult;
|
int handlerResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct WorkerThread_t *next_vacant_thread_slot(void) {
|
static struct WorkerThread_t *next_vacant_thread_slot(void) {
|
||||||
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
|
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
|
||||||
if (! threads[i].thread) return &threads[i];
|
if (! threads[i].thread) return &threads[i];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pthread_mutex_t s_request_queue_lock;
|
static pthread_mutex_t s_request_queue_lock;
|
||||||
|
@ -53,32 +53,32 @@ static int s_last_sequence_number;
|
||||||
static int s_read_pipe, s_write_pipe;
|
static int s_read_pipe, s_write_pipe;
|
||||||
|
|
||||||
static void iothread_init(void) {
|
static void iothread_init(void) {
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
if (! inited) {
|
if (! inited) {
|
||||||
inited = true;
|
inited = true;
|
||||||
|
|
||||||
/* Initialize the queue lock */
|
/* Initialize the queue lock */
|
||||||
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL));
|
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL));
|
||||||
|
|
||||||
/* Initialize the completion pipes */
|
/* Initialize the completion pipes */
|
||||||
int pipes[2] = {0, 0};
|
int pipes[2] = {0, 0};
|
||||||
VOMIT_ON_FAILURE(pipe(pipes));
|
VOMIT_ON_FAILURE(pipe(pipes));
|
||||||
s_read_pipe = pipes[0];
|
s_read_pipe = pipes[0];
|
||||||
s_write_pipe = pipes[1];
|
s_write_pipe = pipes[1];
|
||||||
|
|
||||||
// 0 means success to VOMIT_ON_FAILURE. Arrange to pass 0 if fcntl returns anything other than -1.
|
// 0 means success to VOMIT_ON_FAILURE. Arrange to pass 0 if fcntl returns anything other than -1.
|
||||||
VOMIT_ON_FAILURE(-1 == fcntl(s_read_pipe, F_SETFD, FD_CLOEXEC));
|
VOMIT_ON_FAILURE(-1 == fcntl(s_read_pipe, F_SETFD, FD_CLOEXEC));
|
||||||
VOMIT_ON_FAILURE(-1 == fcntl(s_write_pipe, F_SETFD, FD_CLOEXEC));
|
VOMIT_ON_FAILURE(-1 == fcntl(s_write_pipe, F_SETFD, FD_CLOEXEC));
|
||||||
|
|
||||||
/* Tell each thread its index */
|
/* Tell each thread its index */
|
||||||
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
|
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
|
||||||
threads[i].idx = i;
|
threads[i].idx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_to_queue(struct ThreadedRequest_t *req) {
|
static void add_to_queue(struct ThreadedRequest_t *req) {
|
||||||
ASSERT_IS_LOCKED(s_request_queue_lock);
|
ASSERT_IS_LOCKED(s_request_queue_lock);
|
||||||
s_request_queue.push(req);
|
s_request_queue.push(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,67 +94,67 @@ static ThreadedRequest_t *dequeue_request(void) {
|
||||||
|
|
||||||
/* The function that does thread work. */
|
/* The function that does thread work. */
|
||||||
static void *iothread_worker(void *threadPtr) {
|
static void *iothread_worker(void *threadPtr) {
|
||||||
assert(threadPtr != NULL);
|
assert(threadPtr != NULL);
|
||||||
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
|
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
|
||||||
|
|
||||||
/* Grab a request off of the queue */
|
/* Grab a request off of the queue */
|
||||||
struct ThreadedRequest_t *req = dequeue_request();
|
struct ThreadedRequest_t *req = dequeue_request();
|
||||||
|
|
||||||
/* Run the handler and store the result */
|
/* Run the handler and store the result */
|
||||||
if (req) {
|
if (req) {
|
||||||
req->handlerResult = req->handler(req->context);
|
req->handlerResult = req->handler(req->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write our index to wake up the main thread */
|
/* Write our index to wake up the main thread */
|
||||||
VOMIT_ON_FAILURE(! write_loop(s_write_pipe, (const char *)&thread->idx, sizeof thread->idx));
|
VOMIT_ON_FAILURE(! write_loop(s_write_pipe, (const char *)&thread->idx, sizeof thread->idx));
|
||||||
|
|
||||||
/* We're done */
|
/* We're done */
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Spawn another thread if there's work to be done. */
|
/* Spawn another thread if there's work to be done. */
|
||||||
static void iothread_spawn_if_needed(void) {
|
static void iothread_spawn_if_needed(void) {
|
||||||
ASSERT_IS_LOCKED(s_request_queue_lock);
|
ASSERT_IS_LOCKED(s_request_queue_lock);
|
||||||
if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS) {
|
if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS) {
|
||||||
struct WorkerThread_t *thread = next_vacant_thread_slot();
|
struct WorkerThread_t *thread = next_vacant_thread_slot();
|
||||||
assert(thread != NULL);
|
assert(thread != NULL);
|
||||||
|
|
||||||
/* The spawned thread inherits our signal mask. We don't want the thread to ever receive signals on the spawned thread, so temporarily block all signals, spawn the thread, and then restore it. */
|
/* The spawned thread inherits our signal mask. We don't want the thread to ever receive signals on the spawned thread, so temporarily block all signals, spawn the thread, and then restore it. */
|
||||||
sigset_t newSet, savedSet;
|
sigset_t newSet, savedSet;
|
||||||
sigfillset(&newSet);
|
sigfillset(&newSet);
|
||||||
VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &newSet, &savedSet));
|
VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &newSet, &savedSet));
|
||||||
|
|
||||||
/* Spawn a thread. */
|
/* Spawn a thread. */
|
||||||
int err;
|
int err;
|
||||||
do {
|
do {
|
||||||
err = 0;
|
err = 0;
|
||||||
if (pthread_create(&thread->thread, NULL, iothread_worker, thread)) {
|
if (pthread_create(&thread->thread, NULL, iothread_worker, thread)) {
|
||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
} while (err == EAGAIN);
|
} while (err == EAGAIN);
|
||||||
|
|
||||||
/* Need better error handling - perhaps try again later. */
|
/* Need better error handling - perhaps try again later. */
|
||||||
assert(err == 0);
|
assert(err == 0);
|
||||||
|
|
||||||
/* Note that we are spawned another thread */
|
/* Note that we are spawned another thread */
|
||||||
s_active_thread_count += 1;
|
s_active_thread_count += 1;
|
||||||
|
|
||||||
/* Restore our sigmask */
|
/* Restore our sigmask */
|
||||||
VOMIT_ON_FAILURE(pthread_sigmask(SIG_SETMASK, &savedSet, NULL));
|
VOMIT_ON_FAILURE(pthread_sigmask(SIG_SETMASK, &savedSet, NULL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(void *, int), void *context) {
|
int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(void *, int), void *context) {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
ASSERT_IS_NOT_FORKED_CHILD();
|
ASSERT_IS_NOT_FORKED_CHILD();
|
||||||
iothread_init();
|
iothread_init();
|
||||||
|
|
||||||
/* Create and initialize a request. */
|
/* Create and initialize a request. */
|
||||||
struct ThreadedRequest_t *req = new ThreadedRequest_t();
|
struct ThreadedRequest_t *req = new ThreadedRequest_t();
|
||||||
req->handler = handler;
|
req->handler = handler;
|
||||||
req->completionCallback = completionCallback;
|
req->completionCallback = completionCallback;
|
||||||
req->context = context;
|
req->context = context;
|
||||||
req->sequenceNumber = ++s_last_sequence_number;
|
req->sequenceNumber = ++s_last_sequence_number;
|
||||||
|
|
||||||
/* Take our lock */
|
/* Take our lock */
|
||||||
scoped_lock lock(s_request_queue_lock);
|
scoped_lock lock(s_request_queue_lock);
|
||||||
|
@ -168,38 +168,38 @@ int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(voi
|
||||||
}
|
}
|
||||||
|
|
||||||
int iothread_port(void) {
|
int iothread_port(void) {
|
||||||
iothread_init();
|
iothread_init();
|
||||||
return s_read_pipe;
|
return s_read_pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iothread_service_completion(void) {
|
void iothread_service_completion(void) {
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
|
ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
|
||||||
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
|
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
|
||||||
assert(threadIdx < IO_MAX_THREADS);
|
assert(threadIdx < IO_MAX_THREADS);
|
||||||
|
|
||||||
struct WorkerThread_t *thread = &threads[threadIdx];
|
struct WorkerThread_t *thread = &threads[threadIdx];
|
||||||
assert(thread->thread != 0);
|
assert(thread->thread != 0);
|
||||||
|
|
||||||
struct ThreadedRequest_t *req = NULL;
|
struct ThreadedRequest_t *req = NULL;
|
||||||
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
|
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
|
||||||
|
|
||||||
/* Free up this thread */
|
/* Free up this thread */
|
||||||
thread->thread = 0;
|
thread->thread = 0;
|
||||||
assert(s_active_thread_count > 0);
|
assert(s_active_thread_count > 0);
|
||||||
s_active_thread_count -= 1;
|
s_active_thread_count -= 1;
|
||||||
|
|
||||||
/* Handle the request */
|
/* Handle the request */
|
||||||
if (req) {
|
if (req) {
|
||||||
if (req->completionCallback)
|
if (req->completionCallback)
|
||||||
req->completionCallback(req->context, req->handlerResult);
|
req->completionCallback(req->context, req->handlerResult);
|
||||||
delete req;
|
delete req;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Maybe spawn another thread, if there's more work to be done. */
|
/* Maybe spawn another thread, if there's more work to be done. */
|
||||||
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock));
|
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock));
|
||||||
iothread_spawn_if_needed();
|
iothread_spawn_if_needed();
|
||||||
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock));
|
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
void iothread_drain_all(void) {
|
void iothread_drain_all(void) {
|
||||||
|
|
116
key_reader.cpp
116
key_reader.cpp
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
A small utility to print the resulting key codes from pressing a
|
A small utility to print the resulting key codes from pressing a
|
||||||
key. Servers the same function as hitting ^V in bash, but I prefer
|
key. Servers the same function as hitting ^V in bash, but I prefer
|
||||||
the way key_reader works.
|
the way key_reader works.
|
||||||
|
|
||||||
Type ^C to exit the program.
|
Type ^C to exit the program.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -22,76 +22,76 @@
|
||||||
|
|
||||||
int writestr( char *str )
|
int writestr( char *str )
|
||||||
{
|
{
|
||||||
write( 1, str, strlen(str) );
|
write( 1, str, strlen(str) );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main( int argc, char **argv)
|
int main( int argc, char **argv)
|
||||||
{
|
{
|
||||||
set_main_thread();
|
set_main_thread();
|
||||||
setup_fork_guards();
|
setup_fork_guards();
|
||||||
setlocale( LC_ALL, "" );
|
setlocale( LC_ALL, "" );
|
||||||
|
|
||||||
|
|
||||||
if( argc == 2 )
|
if( argc == 2 )
|
||||||
{
|
{
|
||||||
static char term_buffer[2048];
|
static char term_buffer[2048];
|
||||||
char *termtype = getenv ("TERM");
|
char *termtype = getenv ("TERM");
|
||||||
char *tbuff = new char[9999];
|
char *tbuff = new char[9999];
|
||||||
char *res;
|
char *res;
|
||||||
|
|
||||||
tgetent( term_buffer, termtype );
|
tgetent( term_buffer, termtype );
|
||||||
res = tgetstr( argv[1], &tbuff );
|
res = tgetstr( argv[1], &tbuff );
|
||||||
if( res != 0 )
|
if( res != 0 )
|
||||||
{
|
{
|
||||||
while( *res != 0 )
|
while( *res != 0 )
|
||||||
{
|
{
|
||||||
printf("%d ", *res );
|
printf("%d ", *res );
|
||||||
|
|
||||||
|
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Undefined sequence\n");
|
printf("Undefined sequence\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char scratch[1024];
|
char scratch[1024];
|
||||||
unsigned int c;
|
unsigned int c;
|
||||||
|
|
||||||
struct termios modes, /* so we can change the modes */
|
struct termios modes, /* so we can change the modes */
|
||||||
savemodes; /* so we can reset the modes when we're done */
|
savemodes; /* so we can reset the modes when we're done */
|
||||||
|
|
||||||
input_common_init(0);
|
input_common_init(0);
|
||||||
|
|
||||||
|
|
||||||
tcgetattr(0,&modes); /* get the current terminal modes */
|
tcgetattr(0,&modes); /* get the current terminal modes */
|
||||||
savemodes = modes; /* save a copy so we can reset them */
|
savemodes = modes; /* save a copy so we can reset them */
|
||||||
|
|
||||||
modes.c_lflag &= ~ICANON; /* turn off canonical mode */
|
modes.c_lflag &= ~ICANON; /* turn off canonical mode */
|
||||||
modes.c_lflag &= ~ECHO; /* turn off echo mode */
|
modes.c_lflag &= ~ECHO; /* turn off echo mode */
|
||||||
modes.c_cc[VMIN]=1;
|
modes.c_cc[VMIN]=1;
|
||||||
modes.c_cc[VTIME]=0;
|
modes.c_cc[VTIME]=0;
|
||||||
tcsetattr(0,TCSANOW,&modes); /* set the new modes */
|
tcsetattr(0,TCSANOW,&modes); /* set the new modes */
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
if( (c=input_common_readch(0)) == EOF )
|
if( (c=input_common_readch(0)) == EOF )
|
||||||
break;
|
break;
|
||||||
if( (c > 31) && (c != 127) )
|
if( (c > 31) && (c != 127) )
|
||||||
sprintf( scratch, "dec: %d hex: %x char: %c\n", c, c, c );
|
sprintf( scratch, "dec: %d hex: %x char: %c\n", c, c, c );
|
||||||
else
|
else
|
||||||
sprintf( scratch, "dec: %d hex: %x\n", c, c );
|
sprintf( scratch, "dec: %d hex: %x\n", c, c );
|
||||||
writestr( scratch );
|
writestr( scratch );
|
||||||
}
|
}
|
||||||
/* reset the terminal to the saved mode */
|
/* reset the terminal to the saved mode */
|
||||||
tcsetattr(0,TCSANOW,&savemodes);
|
tcsetattr(0,TCSANOW,&savemodes);
|
||||||
|
|
||||||
input_common_destroy();
|
input_common_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
146
kill.cpp
146
kill.cpp
|
@ -1,9 +1,9 @@
|
||||||
/** \file kill.c
|
/** \file kill.c
|
||||||
The killring.
|
The killring.
|
||||||
|
|
||||||
Works like the killring in emacs and readline. The killring is cut
|
Works like the killring in emacs and readline. The killring is cut
|
||||||
and paste with a memory of previous cuts. It supports integration
|
and paste with a memory of previous cuts. It supports integration
|
||||||
with the X clipboard.
|
with the X clipboard.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -57,12 +57,12 @@ static wchar_t *cut_buffer=0;
|
||||||
*/
|
*/
|
||||||
static int has_xsel()
|
static int has_xsel()
|
||||||
{
|
{
|
||||||
static int res=-1;
|
static int res=-1;
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
res = !! path_get_path(L"xsel", NULL);
|
res = !! path_get_path(L"xsel", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill_add( const wcstring &str )
|
void kill_add( const wcstring &str )
|
||||||
|
@ -71,56 +71,56 @@ void kill_add( const wcstring &str )
|
||||||
if (str.empty())
|
if (str.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wcstring cmd;
|
wcstring cmd;
|
||||||
wchar_t *escaped_str = NULL;
|
wchar_t *escaped_str = NULL;
|
||||||
kill_list.push_front(str);
|
kill_list.push_front(str);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check to see if user has set the FISH_CLIPBOARD_CMD variable,
|
Check to see if user has set the FISH_CLIPBOARD_CMD variable,
|
||||||
and, if so, use it instead of checking the display, etc.
|
and, if so, use it instead of checking the display, etc.
|
||||||
|
|
||||||
I couldn't think of a safe way to allow overide of the echo
|
I couldn't think of a safe way to allow overide of the echo
|
||||||
command too, so, the command used must accept the input via stdin.
|
command too, so, the command used must accept the input via stdin.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const env_var_t clipboard_wstr = env_get_string(L"FISH_CLIPBOARD_CMD");
|
const env_var_t clipboard_wstr = env_get_string(L"FISH_CLIPBOARD_CMD");
|
||||||
if( !clipboard_wstr.missing() )
|
if( !clipboard_wstr.missing() )
|
||||||
{
|
{
|
||||||
escaped_str = escape( str.c_str(), 1 );
|
escaped_str = escape( str.c_str(), 1 );
|
||||||
cmd.assign(L"echo -n ");
|
cmd.assign(L"echo -n ");
|
||||||
cmd.append(escaped_str);
|
cmd.append(escaped_str);
|
||||||
cmd.append(clipboard_wstr);
|
cmd.append(clipboard_wstr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This is for sending the kill to the X copy-and-paste buffer */
|
/* This is for sending the kill to the X copy-and-paste buffer */
|
||||||
if( !has_xsel() ) {
|
if( !has_xsel() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const env_var_t disp_wstr = env_get_string( L"DISPLAY" );
|
const env_var_t disp_wstr = env_get_string( L"DISPLAY" );
|
||||||
if( !disp_wstr.missing() )
|
if( !disp_wstr.missing() )
|
||||||
{
|
{
|
||||||
escaped_str = escape( str.c_str(), 1 );
|
escaped_str = escape( str.c_str(), 1 );
|
||||||
cmd.assign(L"echo ");
|
cmd.assign(L"echo ");
|
||||||
cmd.append(escaped_str);
|
cmd.append(escaped_str);
|
||||||
cmd.append(L"|xsel -b" );
|
cmd.append(L"|xsel -b" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! cmd.empty())
|
if (! cmd.empty())
|
||||||
{
|
{
|
||||||
if( exec_subshell(cmd) == -1 )
|
if( exec_subshell(cmd) == -1 )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Do nothing on failiure
|
Do nothing on failiure
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
free( cut_buffer );
|
free( cut_buffer );
|
||||||
|
|
||||||
cut_buffer = escaped_str;
|
cut_buffer = escaped_str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,8 +138,8 @@ static void kill_remove( const wcstring &s )
|
||||||
|
|
||||||
void kill_replace( const wcstring &old, const wcstring &newv )
|
void kill_replace( const wcstring &old, const wcstring &newv )
|
||||||
{
|
{
|
||||||
kill_remove( old );
|
kill_remove( old );
|
||||||
kill_add( newv );
|
kill_add( newv );
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *kill_yank_rotate()
|
const wchar_t *kill_yank_rotate()
|
||||||
|
@ -160,33 +160,33 @@ const wchar_t *kill_yank_rotate()
|
||||||
*/
|
*/
|
||||||
static void kill_check_x_buffer()
|
static void kill_check_x_buffer()
|
||||||
{
|
{
|
||||||
if( !has_xsel() )
|
if( !has_xsel() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const env_var_t disp = env_get_string(L"DISPLAY");
|
const env_var_t disp = env_get_string(L"DISPLAY");
|
||||||
if( ! disp.missing())
|
if( ! disp.missing())
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
wcstring cmd = L"xsel -t 500 -b";
|
wcstring cmd = L"xsel -t 500 -b";
|
||||||
wcstring new_cut_buffer=L"";
|
wcstring new_cut_buffer=L"";
|
||||||
wcstring_list_t list;
|
wcstring_list_t list;
|
||||||
if( exec_subshell( cmd, list ) != -1 )
|
if( exec_subshell( cmd, list ) != -1 )
|
||||||
{
|
{
|
||||||
|
|
||||||
for( i=0; i<list.size(); i++ )
|
for( i=0; i<list.size(); i++ )
|
||||||
{
|
{
|
||||||
wcstring next_line = escape_string( list.at(i), 0 );
|
wcstring next_line = escape_string( list.at(i), 0 );
|
||||||
if (i > 0) new_cut_buffer += L"\\n";
|
if (i > 0) new_cut_buffer += L"\\n";
|
||||||
new_cut_buffer += next_line;
|
new_cut_buffer += next_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( new_cut_buffer.size() > 0 )
|
if( new_cut_buffer.size() > 0 )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The buffer is inserted with backslash escapes,
|
The buffer is inserted with backslash escapes,
|
||||||
since we don't really like tabs, newlines,
|
since we don't really like tabs, newlines,
|
||||||
etc. anyway.
|
etc. anyway.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cut_buffer == NULL || cut_buffer != new_cut_buffer)
|
if (cut_buffer == NULL || cut_buffer != new_cut_buffer)
|
||||||
{
|
{
|
||||||
|
@ -194,15 +194,15 @@ static void kill_check_x_buffer()
|
||||||
cut_buffer = wcsdup(new_cut_buffer.c_str());
|
cut_buffer = wcsdup(new_cut_buffer.c_str());
|
||||||
kill_list.push_front( new_cut_buffer );
|
kill_list.push_front( new_cut_buffer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const wchar_t *kill_yank()
|
const wchar_t *kill_yank()
|
||||||
{
|
{
|
||||||
kill_check_x_buffer();
|
kill_check_x_buffer();
|
||||||
if (kill_list.empty()) {
|
if (kill_list.empty()) {
|
||||||
return L"";
|
return L"";
|
||||||
} else {
|
} else {
|
||||||
|
@ -220,7 +220,7 @@ void kill_init()
|
||||||
|
|
||||||
void kill_destroy()
|
void kill_destroy()
|
||||||
{
|
{
|
||||||
if( cut_buffer )
|
if( cut_buffer )
|
||||||
free( cut_buffer );
|
free( cut_buffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
kill.h
4
kill.h
|
@ -1,7 +1,7 @@
|
||||||
/** \file kill.h
|
/** \file kill.h
|
||||||
Prototypes for the killring.
|
Prototypes for the killring.
|
||||||
|
|
||||||
Works like the killring in emacs and readline. The killring is cut and paste whith a memory of previous cuts.
|
Works like the killring in emacs and readline. The killring is cut and paste whith a memory of previous cuts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_KILL_H
|
#ifndef FISH_KILL_H
|
||||||
|
|
1920
mimedb.cpp
1920
mimedb.cpp
File diff suppressed because it is too large
Load diff
518
output.cpp
518
output.cpp
|
@ -69,17 +69,17 @@ static int writeb_internal( char c );
|
||||||
*/
|
*/
|
||||||
static const wchar_t *col[]=
|
static const wchar_t *col[]=
|
||||||
{
|
{
|
||||||
L"black",
|
L"black",
|
||||||
L"red",
|
L"red",
|
||||||
L"green",
|
L"green",
|
||||||
L"brown",
|
L"brown",
|
||||||
L"yellow",
|
L"yellow",
|
||||||
L"blue",
|
L"blue",
|
||||||
L"magenta",
|
L"magenta",
|
||||||
L"purple",
|
L"purple",
|
||||||
L"cyan",
|
L"cyan",
|
||||||
L"white"
|
L"white"
|
||||||
L"normal"
|
L"normal"
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -91,17 +91,17 @@ static const wchar_t *col[]=
|
||||||
*/
|
*/
|
||||||
static const int col_idx[]=
|
static const int col_idx[]=
|
||||||
{
|
{
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5,
|
5,
|
||||||
5,
|
5,
|
||||||
6,
|
6,
|
||||||
7,
|
7,
|
||||||
FISH_COLOR_NORMAL,
|
FISH_COLOR_NORMAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,13 +121,13 @@ static bool support_term256 = false;
|
||||||
|
|
||||||
void output_set_writer( int (*writer)(char) )
|
void output_set_writer( int (*writer)(char) )
|
||||||
{
|
{
|
||||||
CHECK( writer, );
|
CHECK( writer, );
|
||||||
out = writer;
|
out = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int (*output_get_writer())(char)
|
int (*output_get_writer())(char)
|
||||||
{
|
{
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool term256_support_is_native(void) {
|
static bool term256_support_is_native(void) {
|
||||||
|
@ -212,177 +212,177 @@ void set_color(rgb_color_t c, rgb_color_t c2)
|
||||||
|
|
||||||
const rgb_color_t normal = rgb_color_t::normal();
|
const rgb_color_t normal = rgb_color_t::normal();
|
||||||
static rgb_color_t last_color = rgb_color_t::normal();
|
static rgb_color_t last_color = rgb_color_t::normal();
|
||||||
static rgb_color_t last_color2 = rgb_color_t::normal();
|
static rgb_color_t last_color2 = rgb_color_t::normal();
|
||||||
static int was_bold=0;
|
static int was_bold=0;
|
||||||
static int was_underline=0;
|
static int was_underline=0;
|
||||||
int bg_set=0, last_bg_set=0;
|
int bg_set=0, last_bg_set=0;
|
||||||
|
|
||||||
int is_bold = 0;
|
int is_bold = 0;
|
||||||
int is_underline = 0;
|
int is_underline = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test if we have at least basic support for setting fonts, colors
|
Test if we have at least basic support for setting fonts, colors
|
||||||
and related bits - otherwise just give up...
|
and related bits - otherwise just give up...
|
||||||
*/
|
*/
|
||||||
if( !exit_attribute_mode )
|
if( !exit_attribute_mode )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
is_bold |= c.is_bold();
|
is_bold |= c.is_bold();
|
||||||
is_bold |= c2.is_bold();
|
is_bold |= c2.is_bold();
|
||||||
|
|
||||||
is_underline |= c.is_underline();
|
is_underline |= c.is_underline();
|
||||||
is_underline |= c2.is_underline();
|
is_underline |= c2.is_underline();
|
||||||
|
|
||||||
if( c.is_reset() || c2.is_reset())
|
if( c.is_reset() || c2.is_reset())
|
||||||
{
|
{
|
||||||
c = c2 = normal;
|
c = c2 = normal;
|
||||||
was_bold=0;
|
was_bold=0;
|
||||||
was_underline=0;
|
was_underline=0;
|
||||||
/*
|
/*
|
||||||
If we exit attibute mode, we must first set a color, or
|
If we exit attibute mode, we must first set a color, or
|
||||||
previously coloured text might lose it's
|
previously coloured text might lose it's
|
||||||
color. Terminals are weird...
|
color. Terminals are weird...
|
||||||
*/
|
*/
|
||||||
write_foreground_color(0);
|
write_foreground_color(0);
|
||||||
writembs( exit_attribute_mode );
|
writembs( exit_attribute_mode );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( was_bold && !is_bold )
|
if( was_bold && !is_bold )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Only way to exit bold mode is a reset of all attributes.
|
Only way to exit bold mode is a reset of all attributes.
|
||||||
*/
|
*/
|
||||||
writembs( exit_attribute_mode );
|
writembs( exit_attribute_mode );
|
||||||
last_color = normal;
|
last_color = normal;
|
||||||
last_color2 = normal;
|
last_color2 = normal;
|
||||||
was_bold=0;
|
was_bold=0;
|
||||||
was_underline=0;
|
was_underline=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ! last_color2.is_normal() &&
|
if( ! last_color2.is_normal() &&
|
||||||
! last_color2.is_reset() &&
|
! last_color2.is_reset() &&
|
||||||
! last_color2.is_ignore() )
|
! last_color2.is_ignore() )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Background was set
|
Background was set
|
||||||
*/
|
*/
|
||||||
last_bg_set=1;
|
last_bg_set=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ! c2.is_normal() &&
|
if( ! c2.is_normal() &&
|
||||||
! c2.is_ignore())
|
! c2.is_ignore())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Background is set
|
Background is set
|
||||||
*/
|
*/
|
||||||
bg_set=1;
|
bg_set=1;
|
||||||
if ( c==c2 )
|
if ( c==c2 )
|
||||||
c = (c2==rgb_color_t::white())?rgb_color_t::black():rgb_color_t::white();
|
c = (c2==rgb_color_t::white())?rgb_color_t::black():rgb_color_t::white();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0))
|
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0))
|
||||||
{
|
{
|
||||||
if(bg_set && !last_bg_set)
|
if(bg_set && !last_bg_set)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Background color changed and is set, so we enter bold
|
Background color changed and is set, so we enter bold
|
||||||
mode to make reading easier. This means bold mode is
|
mode to make reading easier. This means bold mode is
|
||||||
_always_ on when the background color is set.
|
_always_ on when the background color is set.
|
||||||
*/
|
*/
|
||||||
writembs( enter_bold_mode );
|
writembs( enter_bold_mode );
|
||||||
}
|
}
|
||||||
if(!bg_set && last_bg_set)
|
if(!bg_set && last_bg_set)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Background color changed and is no longer set, so we
|
Background color changed and is no longer set, so we
|
||||||
exit bold mode
|
exit bold mode
|
||||||
*/
|
*/
|
||||||
writembs( exit_attribute_mode );
|
writembs( exit_attribute_mode );
|
||||||
was_bold=0;
|
was_bold=0;
|
||||||
was_underline=0;
|
was_underline=0;
|
||||||
/*
|
/*
|
||||||
We don't know if exit_attribute_mode resets colors, so
|
We don't know if exit_attribute_mode resets colors, so
|
||||||
we set it to something known.
|
we set it to something known.
|
||||||
*/
|
*/
|
||||||
if( write_foreground_color(0))
|
if( write_foreground_color(0))
|
||||||
{
|
{
|
||||||
last_color=rgb_color_t::black();
|
last_color=rgb_color_t::black();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( last_color != c )
|
if( last_color != c )
|
||||||
{
|
{
|
||||||
if( c.is_normal() )
|
if( c.is_normal() )
|
||||||
{
|
{
|
||||||
write_foreground_color(0);
|
write_foreground_color(0);
|
||||||
writembs( exit_attribute_mode );
|
writembs( exit_attribute_mode );
|
||||||
|
|
||||||
last_color2 = rgb_color_t::normal();
|
last_color2 = rgb_color_t::normal();
|
||||||
was_bold=0;
|
was_bold=0;
|
||||||
was_underline=0;
|
was_underline=0;
|
||||||
}
|
}
|
||||||
else if( ! c.is_special() )
|
else if( ! c.is_special() )
|
||||||
{
|
{
|
||||||
write_foreground_color(index_for_color(c));
|
write_foreground_color(index_for_color(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
last_color = c;
|
last_color = c;
|
||||||
|
|
||||||
if( last_color2 != c2 )
|
if( last_color2 != c2 )
|
||||||
{
|
{
|
||||||
if( c2.is_normal() )
|
if( c2.is_normal() )
|
||||||
{
|
{
|
||||||
write_background_color(0);
|
write_background_color(0);
|
||||||
|
|
||||||
writembs( exit_attribute_mode );
|
writembs( exit_attribute_mode );
|
||||||
if( ! last_color.is_normal())
|
if( ! last_color.is_normal())
|
||||||
{
|
{
|
||||||
write_foreground_color(index_for_color(last_color));
|
write_foreground_color(index_for_color(last_color));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
was_bold=0;
|
was_bold=0;
|
||||||
was_underline=0;
|
was_underline=0;
|
||||||
last_color2 = c2;
|
last_color2 = c2;
|
||||||
}
|
}
|
||||||
else if ( ! c2.is_special() )
|
else if ( ! c2.is_special() )
|
||||||
{
|
{
|
||||||
write_background_color(index_for_color(c2));
|
write_background_color(index_for_color(c2));
|
||||||
last_color2 = c2;
|
last_color2 = c2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Lastly, we set bold mode and underline mode correctly
|
Lastly, we set bold mode and underline mode correctly
|
||||||
*/
|
*/
|
||||||
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set )
|
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set )
|
||||||
{
|
{
|
||||||
if( is_bold && !was_bold )
|
if( is_bold && !was_bold )
|
||||||
{
|
{
|
||||||
if( enter_bold_mode )
|
if( enter_bold_mode )
|
||||||
{
|
{
|
||||||
writembs( tparm( enter_bold_mode ) );
|
writembs( tparm( enter_bold_mode ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
was_bold = is_bold;
|
was_bold = is_bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( was_underline && !is_underline )
|
if( was_underline && !is_underline )
|
||||||
{
|
{
|
||||||
writembs( exit_underline_mode );
|
writembs( exit_underline_mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !was_underline && is_underline )
|
if( !was_underline && is_underline )
|
||||||
{
|
{
|
||||||
writembs( enter_underline_mode );
|
writembs( enter_underline_mode );
|
||||||
}
|
}
|
||||||
was_underline = is_underline;
|
was_underline = is_underline;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,80 +391,80 @@ void set_color(rgb_color_t c, rgb_color_t c2)
|
||||||
*/
|
*/
|
||||||
static int writeb_internal( char c )
|
static int writeb_internal( char c )
|
||||||
{
|
{
|
||||||
write_loop( 1, &c, 1 );
|
write_loop( 1, &c, 1 );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int writeb( tputs_arg_t b )
|
int writeb( tputs_arg_t b )
|
||||||
{
|
{
|
||||||
out( b );
|
out( b );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int writembs_internal( char *str )
|
int writembs_internal( char *str )
|
||||||
{
|
{
|
||||||
CHECK( str, 1 );
|
CHECK( str, 1 );
|
||||||
|
|
||||||
return tputs(str,1,&writeb)==ERR?1:0;
|
return tputs(str,1,&writeb)==ERR?1:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int writech( wint_t ch )
|
int writech( wint_t ch )
|
||||||
{
|
{
|
||||||
mbstate_t state;
|
mbstate_t state;
|
||||||
size_t i;
|
size_t i;
|
||||||
char buff[MB_LEN_MAX+1];
|
char buff[MB_LEN_MAX+1];
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
|
|
||||||
if( ( ch >= ENCODE_DIRECT_BASE) &&
|
if( ( ch >= ENCODE_DIRECT_BASE) &&
|
||||||
( ch < ENCODE_DIRECT_BASE+256) )
|
( ch < ENCODE_DIRECT_BASE+256) )
|
||||||
{
|
{
|
||||||
buff[0] = ch - ENCODE_DIRECT_BASE;
|
buff[0] = ch - ENCODE_DIRECT_BASE;
|
||||||
bytes=1;
|
bytes=1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memset( &state, 0, sizeof(state) );
|
memset( &state, 0, sizeof(state) );
|
||||||
bytes= wcrtomb( buff, ch, &state );
|
bytes= wcrtomb( buff, ch, &state );
|
||||||
|
|
||||||
switch( bytes )
|
switch( bytes )
|
||||||
{
|
{
|
||||||
case (size_t)(-1):
|
case (size_t)(-1):
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for( i=0; i<bytes; i++ )
|
for( i=0; i<bytes; i++ )
|
||||||
{
|
{
|
||||||
out( buff[i] );
|
out( buff[i] );
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writestr( const wchar_t *str )
|
void writestr( const wchar_t *str )
|
||||||
{
|
{
|
||||||
char *pos;
|
char *pos;
|
||||||
|
|
||||||
CHECK( str, );
|
CHECK( str, );
|
||||||
|
|
||||||
// while( *str )
|
// while( *str )
|
||||||
// writech( *str++ );
|
// writech( *str++ );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check amount of needed space
|
Check amount of needed space
|
||||||
*/
|
*/
|
||||||
size_t len = wcstombs( 0, str, 0 );
|
size_t len = wcstombs( 0, str, 0 );
|
||||||
|
|
||||||
if( len == (size_t)-1 )
|
if( len == (size_t)-1 )
|
||||||
{
|
{
|
||||||
debug( 1, L"Tried to print invalid wide character string" );
|
debug( 1, L"Tried to print invalid wide character string" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
len++;
|
len++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert
|
Convert
|
||||||
*/
|
*/
|
||||||
char *buffer, static_buffer[256];
|
char *buffer, static_buffer[256];
|
||||||
|
@ -473,17 +473,17 @@ void writestr( const wchar_t *str )
|
||||||
else
|
else
|
||||||
buffer = new char[len];
|
buffer = new char[len];
|
||||||
|
|
||||||
wcstombs( buffer,
|
wcstombs( buffer,
|
||||||
str,
|
str,
|
||||||
len );
|
len );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Write
|
Write
|
||||||
*/
|
*/
|
||||||
for( pos = buffer; *pos; pos++ )
|
for( pos = buffer; *pos; pos++ )
|
||||||
{
|
{
|
||||||
out( *pos );
|
out( *pos );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer != static_buffer)
|
if (buffer != static_buffer)
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
@ -492,93 +492,93 @@ void writestr( const wchar_t *str )
|
||||||
|
|
||||||
void writestr_ellipsis( const wchar_t *str, int max_width )
|
void writestr_ellipsis( const wchar_t *str, int max_width )
|
||||||
{
|
{
|
||||||
int written=0;
|
int written=0;
|
||||||
int tot;
|
int tot;
|
||||||
|
|
||||||
CHECK( str, );
|
CHECK( str, );
|
||||||
|
|
||||||
tot = my_wcswidth(str);
|
tot = my_wcswidth(str);
|
||||||
|
|
||||||
if( tot <= max_width )
|
if( tot <= max_width )
|
||||||
{
|
{
|
||||||
writestr( str );
|
writestr( str );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( *str != 0 )
|
while( *str != 0 )
|
||||||
{
|
{
|
||||||
int w = fish_wcwidth( *str );
|
int w = fish_wcwidth( *str );
|
||||||
if( written+w+fish_wcwidth( ellipsis_char )>max_width )
|
if( written+w+fish_wcwidth( ellipsis_char )>max_width )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
written+=w;
|
written+=w;
|
||||||
writech( *(str++) );
|
writech( *(str++) );
|
||||||
}
|
}
|
||||||
|
|
||||||
written += fish_wcwidth( ellipsis_char );
|
written += fish_wcwidth( ellipsis_char );
|
||||||
writech( ellipsis_char );
|
writech( ellipsis_char );
|
||||||
|
|
||||||
while( written < max_width )
|
while( written < max_width )
|
||||||
{
|
{
|
||||||
written++;
|
written++;
|
||||||
writestr( L" " );
|
writestr( L" " );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_escaped_str( const wchar_t *str, int max_len )
|
int write_escaped_str( const wchar_t *str, int max_len )
|
||||||
{
|
{
|
||||||
|
|
||||||
wchar_t *out;
|
wchar_t *out;
|
||||||
int i;
|
int i;
|
||||||
int len;
|
int len;
|
||||||
int written=0;
|
int written=0;
|
||||||
|
|
||||||
CHECK( str, 0 );
|
CHECK( str, 0 );
|
||||||
|
|
||||||
out = escape( str, 1 );
|
out = escape( str, 1 );
|
||||||
len = my_wcswidth( out );
|
len = my_wcswidth( out );
|
||||||
|
|
||||||
if( max_len && (max_len < len))
|
if( max_len && (max_len < len))
|
||||||
{
|
{
|
||||||
for( i=0; (written+fish_wcwidth(out[i]))<=(max_len-1); i++ )
|
for( i=0; (written+fish_wcwidth(out[i]))<=(max_len-1); i++ )
|
||||||
{
|
{
|
||||||
writech( out[i] );
|
writech( out[i] );
|
||||||
written += fish_wcwidth( out[i] );
|
written += fish_wcwidth( out[i] );
|
||||||
}
|
}
|
||||||
writech( ellipsis_char );
|
writech( ellipsis_char );
|
||||||
written += fish_wcwidth( ellipsis_char );
|
written += fish_wcwidth( ellipsis_char );
|
||||||
|
|
||||||
for( i=written; i<max_len; i++ )
|
for( i=written; i<max_len; i++ )
|
||||||
{
|
{
|
||||||
writech( L' ' );
|
writech( L' ' );
|
||||||
written++;
|
written++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
written = len;
|
written = len;
|
||||||
writestr( out );
|
writestr( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
free( out );
|
free( out );
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int output_color_code( const wcstring &val, bool is_background ) {
|
int output_color_code( const wcstring &val, bool is_background ) {
|
||||||
size_t i;
|
size_t i;
|
||||||
int color=FISH_COLOR_NORMAL;
|
int color=FISH_COLOR_NORMAL;
|
||||||
int is_bold=0;
|
int is_bold=0;
|
||||||
int is_underline=0;
|
int is_underline=0;
|
||||||
|
|
||||||
if (val.empty())
|
if (val.empty())
|
||||||
return FISH_COLOR_NORMAL;
|
return FISH_COLOR_NORMAL;
|
||||||
|
|
||||||
wcstring_list_t el;
|
wcstring_list_t el;
|
||||||
tokenize_variable_array( val, el );
|
tokenize_variable_array( val, el );
|
||||||
|
|
||||||
for(size_t j=0; j < el.size(); j++ ) {
|
for(size_t j=0; j < el.size(); j++ ) {
|
||||||
const wcstring &next = el.at(j);
|
const wcstring &next = el.at(j);
|
||||||
wcstring color_name;
|
wcstring color_name;
|
||||||
if (is_background) {
|
if (is_background) {
|
||||||
|
@ -608,21 +608,21 @@ int output_color_code( const wcstring &val, bool is_background ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return color | (is_bold?FISH_COLOR_BOLD:0) | (is_underline?FISH_COLOR_UNDERLINE:0);
|
return color | (is_bold?FISH_COLOR_BOLD:0) | (is_underline?FISH_COLOR_UNDERLINE:0);
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t parse_color( const wcstring &val, bool is_background ) {
|
rgb_color_t parse_color( const wcstring &val, bool is_background ) {
|
||||||
int is_bold=0;
|
int is_bold=0;
|
||||||
int is_underline=0;
|
int is_underline=0;
|
||||||
|
|
||||||
std::vector<rgb_color_t> candidates;
|
std::vector<rgb_color_t> candidates;
|
||||||
|
|
||||||
wcstring_list_t el;
|
wcstring_list_t el;
|
||||||
tokenize_variable_array( val, el );
|
tokenize_variable_array( val, el );
|
||||||
|
|
||||||
for(size_t j=0; j < el.size(); j++ ) {
|
for(size_t j=0; j < el.size(); j++ ) {
|
||||||
const wcstring &next = el.at(j);
|
const wcstring &next = el.at(j);
|
||||||
wcstring color_name;
|
wcstring color_name;
|
||||||
if (is_background) {
|
if (is_background) {
|
||||||
|
@ -682,7 +682,7 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) {
|
||||||
|
|
||||||
void output_set_term( const wchar_t *term )
|
void output_set_term( const wchar_t *term )
|
||||||
{
|
{
|
||||||
current_term = term;
|
current_term = term;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *output_get_term()
|
const wchar_t *output_get_term()
|
||||||
|
|
56
output.h
56
output.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file output.h
|
/** \file output.h
|
||||||
Generic output functions
|
Generic output functions
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
Constants for various character classifications. Each character of a command string can be classified as one of the following types.
|
Constants for various character classifications. Each character of a command string can be classified as one of the following types.
|
||||||
|
@ -17,18 +17,18 @@
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FISH_COLOR_BLACK,
|
FISH_COLOR_BLACK,
|
||||||
FISH_COLOR_RED,
|
FISH_COLOR_RED,
|
||||||
FISH_COLOR_GREEN,
|
FISH_COLOR_GREEN,
|
||||||
FISH_COLOR_YELLOW,
|
FISH_COLOR_YELLOW,
|
||||||
FISH_COLOR_BLUE,
|
FISH_COLOR_BLUE,
|
||||||
FISH_COLOR_MAGENTA,
|
FISH_COLOR_MAGENTA,
|
||||||
FISH_COLOR_CYAN,
|
FISH_COLOR_CYAN,
|
||||||
FISH_COLOR_WHITE,
|
FISH_COLOR_WHITE,
|
||||||
/** The default fg color of the terminal */
|
/** The default fg color of the terminal */
|
||||||
FISH_COLOR_NORMAL,
|
FISH_COLOR_NORMAL,
|
||||||
FISH_COLOR_IGNORE,
|
FISH_COLOR_IGNORE,
|
||||||
FISH_COLOR_RESET
|
FISH_COLOR_RESET
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -81,21 +81,21 @@ void set_color(rgb_color_t c, rgb_color_t c2);
|
||||||
#define writembs( mbs ) \
|
#define writembs( mbs ) \
|
||||||
{ \
|
{ \
|
||||||
char *tmp = mbs; \
|
char *tmp = mbs; \
|
||||||
if( tmp ) \
|
if( tmp ) \
|
||||||
{ \
|
{ \
|
||||||
writembs_internal( tmp ); \
|
writembs_internal( tmp ); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
debug( 0, \
|
debug( 0, \
|
||||||
_(L"Tried to use terminfo string %s on line %d of %s, which is undefined in terminal of type \"%ls\". Please report this error to %s"), \
|
_(L"Tried to use terminfo string %s on line %d of %s, which is undefined in terminal of type \"%ls\". Please report this error to %s"), \
|
||||||
#mbs, \
|
#mbs, \
|
||||||
__LINE__, \
|
__LINE__, \
|
||||||
__FILE__, \
|
__FILE__, \
|
||||||
output_get_term(), \
|
output_get_term(), \
|
||||||
PACKAGE_BUGREPORT); \
|
PACKAGE_BUGREPORT); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
1026
parse_util.cpp
1026
parse_util.cpp
File diff suppressed because it is too large
Load diff
34
parse_util.h
34
parse_util.h
|
@ -23,9 +23,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int parse_util_locate_cmdsubst( const wchar_t *in,
|
int parse_util_locate_cmdsubst( const wchar_t *in,
|
||||||
wchar_t **begin,
|
wchar_t **begin,
|
||||||
wchar_t **end,
|
wchar_t **end,
|
||||||
int flags );
|
int flags );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Find the beginning and end of the command substitution under the
|
Find the beginning and end of the command substitution under the
|
||||||
|
@ -40,9 +40,9 @@ int parse_util_locate_cmdsubst( const wchar_t *in,
|
||||||
\param b the end of the searched string
|
\param b the end of the searched string
|
||||||
*/
|
*/
|
||||||
void parse_util_cmdsubst_extent( const wchar_t *buff,
|
void parse_util_cmdsubst_extent( const wchar_t *buff,
|
||||||
size_t cursor_pos,
|
size_t cursor_pos,
|
||||||
const wchar_t **a,
|
const wchar_t **a,
|
||||||
const wchar_t **b );
|
const wchar_t **b );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Find the beginning and end of the process definition under the cursor
|
Find the beginning and end of the process definition under the cursor
|
||||||
|
@ -53,9 +53,9 @@ void parse_util_cmdsubst_extent( const wchar_t *buff,
|
||||||
\param b the end of the searched string
|
\param b the end of the searched string
|
||||||
*/
|
*/
|
||||||
void parse_util_process_extent( const wchar_t *buff,
|
void parse_util_process_extent( const wchar_t *buff,
|
||||||
size_t cursor_pos,
|
size_t cursor_pos,
|
||||||
const wchar_t **a,
|
const wchar_t **a,
|
||||||
const wchar_t **b );
|
const wchar_t **b );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,9 +67,9 @@ void parse_util_process_extent( const wchar_t *buff,
|
||||||
\param b the end of the searched string
|
\param b the end of the searched string
|
||||||
*/
|
*/
|
||||||
void parse_util_job_extent( const wchar_t *buff,
|
void parse_util_job_extent( const wchar_t *buff,
|
||||||
size_t cursor_pos,
|
size_t cursor_pos,
|
||||||
const wchar_t **a,
|
const wchar_t **a,
|
||||||
const wchar_t **b );
|
const wchar_t **b );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Find the beginning and end of the token under the cursor and the
|
Find the beginning and end of the token under the cursor and the
|
||||||
|
@ -84,11 +84,11 @@ void parse_util_job_extent( const wchar_t *buff,
|
||||||
\param prev_end the end of the token before the current token
|
\param prev_end the end of the token before the current token
|
||||||
*/
|
*/
|
||||||
void parse_util_token_extent( const wchar_t *buff,
|
void parse_util_token_extent( const wchar_t *buff,
|
||||||
size_t cursor_pos,
|
size_t cursor_pos,
|
||||||
const wchar_t **tok_begin,
|
const wchar_t **tok_begin,
|
||||||
const wchar_t **tok_end,
|
const wchar_t **tok_end,
|
||||||
const wchar_t **prev_begin,
|
const wchar_t **prev_begin,
|
||||||
const wchar_t **prev_end );
|
const wchar_t **prev_end );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
4670
parser.cpp
4670
parser.cpp
File diff suppressed because it is too large
Load diff
214
parser.h
214
parser.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file parser.h
|
/** \file parser.h
|
||||||
The fish parser.
|
The fish parser.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_PARSER_H
|
#ifndef FISH_PARSER_H
|
||||||
|
@ -21,15 +21,15 @@
|
||||||
*/
|
*/
|
||||||
struct event_blockage_t
|
struct event_blockage_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
The types of events to block. This is interpreted as a bitset
|
The types of events to block. This is interpreted as a bitset
|
||||||
whete the value is 1 for every bit corresponding to a blocked
|
whete the value is 1 for every bit corresponding to a blocked
|
||||||
event type. For example, if EVENT_VARIABLE type events should
|
event type. For example, if EVENT_VARIABLE type events should
|
||||||
be blocked, (type & 1<<EVENT_BLOCKED) should be set.
|
be blocked, (type & 1<<EVENT_BLOCKED) should be set.
|
||||||
|
|
||||||
Note that EVENT_ANY can be used to specify any event.
|
Note that EVENT_ANY can be used to specify any event.
|
||||||
*/
|
*/
|
||||||
unsigned int typemask;
|
unsigned int typemask;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<event_blockage_t> event_blockage_list_t;
|
typedef std::list<event_blockage_t> event_blockage_list_t;
|
||||||
|
@ -46,24 +46,24 @@ inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls, int
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Types of blocks
|
Types of blocks
|
||||||
*/
|
*/
|
||||||
enum block_type_t
|
enum block_type_t
|
||||||
{
|
{
|
||||||
WHILE, /**< While loop block */
|
WHILE, /**< While loop block */
|
||||||
FOR, /**< For loop block */
|
FOR, /**< For loop block */
|
||||||
IF, /**< If block */
|
IF, /**< If block */
|
||||||
FUNCTION_DEF, /**< Function definition block */
|
FUNCTION_DEF, /**< Function definition block */
|
||||||
FUNCTION_CALL, /**< Function invocation block */
|
FUNCTION_CALL, /**< Function invocation block */
|
||||||
FUNCTION_CALL_NO_SHADOW, /**< Function invocation block with no variable shadowing */
|
FUNCTION_CALL_NO_SHADOW, /**< Function invocation block with no variable shadowing */
|
||||||
SWITCH, /**< Switch block */
|
SWITCH, /**< Switch block */
|
||||||
FAKE, /**< Fake block */
|
FAKE, /**< Fake block */
|
||||||
SUBST, /**< Command substitution scope */
|
SUBST, /**< Command substitution scope */
|
||||||
TOP, /**< Outermost block */
|
TOP, /**< Outermost block */
|
||||||
BEGIN, /**< Unconditional block */
|
BEGIN, /**< Unconditional block */
|
||||||
SOURCE, /**< Block created by the . (source) builtin */
|
SOURCE, /**< Block created by the . (source) builtin */
|
||||||
EVENT, /**< Block created on event notifier invocation */
|
EVENT, /**< Block created on event notifier invocation */
|
||||||
BREAKPOINT, /**< Breakpoint block */
|
BREAKPOINT, /**< Breakpoint block */
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ struct block_t
|
||||||
block_t(block_type_t t);
|
block_t(block_type_t t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const block_type_t block_type; /**< Type of block. */
|
const block_type_t block_type; /**< Type of block. */
|
||||||
bool made_fake;
|
bool made_fake;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -86,53 +86,53 @@ struct block_t
|
||||||
/** Mark a block as fake; this is used by the return statement. */
|
/** Mark a block as fake; this is used by the return statement. */
|
||||||
void mark_as_fake() { this->made_fake = true; }
|
void mark_as_fake() { this->made_fake = true; }
|
||||||
|
|
||||||
bool skip; /**< Whether execution of the commands in this block should be skipped */
|
bool skip; /**< Whether execution of the commands in this block should be skipped */
|
||||||
bool had_command; /**< Set to non-zero once a command has been executed in this block */
|
bool had_command; /**< Set to non-zero once a command has been executed in this block */
|
||||||
int tok_pos; /**< The start index of the block */
|
int tok_pos; /**< The start index of the block */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Status for the current loop block. Can be any of the values from the loop_status enum.
|
Status for the current loop block. Can be any of the values from the loop_status enum.
|
||||||
*/
|
*/
|
||||||
int loop_status;
|
int loop_status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The job that is currently evaluated in the specified block.
|
The job that is currently evaluated in the specified block.
|
||||||
*/
|
*/
|
||||||
job_t *job;
|
job_t *job;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int while_state; /**< True if the loop condition has not yet been evaluated*/
|
int while_state; /**< True if the loop condition has not yet been evaluated*/
|
||||||
wchar_t *for_variable; /**< Name of the variable to loop over */
|
wchar_t *for_variable; /**< Name of the variable to loop over */
|
||||||
int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */
|
int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */
|
||||||
wchar_t *switch_value; /**< The value to test in a switch block */
|
wchar_t *switch_value; /**< The value to test in a switch block */
|
||||||
const wchar_t *source_dest; /**< The name of the file to source*/
|
const wchar_t *source_dest; /**< The name of the file to source*/
|
||||||
event_t *event; /**<The event that triggered this block */
|
event_t *event; /**<The event that triggered this block */
|
||||||
wchar_t *function_call_name;
|
wchar_t *function_call_name;
|
||||||
} param1;
|
} param1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Name of file that created this block
|
Name of file that created this block
|
||||||
*/
|
*/
|
||||||
const wchar_t *src_filename;
|
const wchar_t *src_filename;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Line number where this block was created
|
Line number where this block was created
|
||||||
*/
|
*/
|
||||||
int src_lineno;
|
int src_lineno;
|
||||||
|
|
||||||
/** Whether we should pop the environment variable stack when we're popped off of the block stack */
|
/** Whether we should pop the environment variable stack when we're popped off of the block stack */
|
||||||
bool wants_pop_env;
|
bool wants_pop_env;
|
||||||
|
|
||||||
/** List of event blocks. */
|
/** List of event blocks. */
|
||||||
event_blockage_list_t event_blocks;
|
event_blockage_list_t event_blocks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Next outer block
|
Next outer block
|
||||||
*/
|
*/
|
||||||
block_t *outer;
|
block_t *outer;
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
virtual ~block_t();
|
virtual ~block_t();
|
||||||
|
@ -213,9 +213,9 @@ struct breakpoint_block_t : public block_t
|
||||||
*/
|
*/
|
||||||
enum loop_status
|
enum loop_status
|
||||||
{
|
{
|
||||||
LOOP_NORMAL, /**< Current loop block executed as normal */
|
LOOP_NORMAL, /**< Current loop block executed as normal */
|
||||||
LOOP_BREAK, /**< Current loop block should be removed */
|
LOOP_BREAK, /**< Current loop block should be removed */
|
||||||
LOOP_CONTINUE, /**< Current loop block should be skipped */
|
LOOP_CONTINUE, /**< Current loop block should be skipped */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,9 +224,9 @@ enum loop_status
|
||||||
*/
|
*/
|
||||||
enum while_status
|
enum while_status
|
||||||
{
|
{
|
||||||
WHILE_TEST_FIRST, /**< This is the first command of the first lap of a while loop */
|
WHILE_TEST_FIRST, /**< This is the first command of the first lap of a while loop */
|
||||||
WHILE_TEST_AGAIN, /**< This is not the first lap of the while loop, but it is the first command of the loop */
|
WHILE_TEST_AGAIN, /**< This is not the first lap of the while loop, but it is the first command of the loop */
|
||||||
WHILE_TESTED, /**< This is not the first command in the loop */
|
WHILE_TESTED, /**< This is not the first command in the loop */
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -236,22 +236,22 @@ enum while_status
|
||||||
*/
|
*/
|
||||||
enum parser_error
|
enum parser_error
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
No error
|
No error
|
||||||
*/
|
*/
|
||||||
NO_ERR=0,
|
NO_ERR=0,
|
||||||
/**
|
/**
|
||||||
An error in the syntax
|
An error in the syntax
|
||||||
*/
|
*/
|
||||||
SYNTAX_ERROR,
|
SYNTAX_ERROR,
|
||||||
/**
|
/**
|
||||||
Error occured while evaluating commands
|
Error occured while evaluating commands
|
||||||
*/
|
*/
|
||||||
EVAL_ERROR,
|
EVAL_ERROR,
|
||||||
/**
|
/**
|
||||||
Error while evaluating cmdsubst
|
Error while evaluating cmdsubst
|
||||||
*/
|
*/
|
||||||
CMDSUBST_ERROR,
|
CMDSUBST_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum parser_type_t {
|
enum parser_type_t {
|
||||||
|
@ -259,30 +259,30 @@ enum parser_type_t {
|
||||||
PARSER_TYPE_GENERAL,
|
PARSER_TYPE_GENERAL,
|
||||||
PARSER_TYPE_FUNCTIONS_ONLY,
|
PARSER_TYPE_FUNCTIONS_ONLY,
|
||||||
PARSER_TYPE_COMPLETIONS_ONLY,
|
PARSER_TYPE_COMPLETIONS_ONLY,
|
||||||
PARSER_TYPE_ERRORS_ONLY
|
PARSER_TYPE_ERRORS_ONLY
|
||||||
};
|
};
|
||||||
|
|
||||||
struct profile_item_t {
|
struct profile_item_t {
|
||||||
/**
|
/**
|
||||||
Time spent executing the specified command, including parse time for nested blocks.
|
Time spent executing the specified command, including parse time for nested blocks.
|
||||||
*/
|
*/
|
||||||
int exec;
|
int exec;
|
||||||
/**
|
/**
|
||||||
Time spent parsing the specified command, including execution time for command substitutions.
|
Time spent parsing the specified command, including execution time for command substitutions.
|
||||||
*/
|
*/
|
||||||
int parse;
|
int parse;
|
||||||
/**
|
/**
|
||||||
The block level of the specified command. nested blocks and command substitutions both increase the block level.
|
The block level of the specified command. nested blocks and command substitutions both increase the block level.
|
||||||
*/
|
*/
|
||||||
size_t level;
|
size_t level;
|
||||||
/**
|
/**
|
||||||
If the execution of this command was skipped.
|
If the execution of this command was skipped.
|
||||||
*/
|
*/
|
||||||
int skipped;
|
int skipped;
|
||||||
/**
|
/**
|
||||||
The command string.
|
The command string.
|
||||||
*/
|
*/
|
||||||
wcstring cmd;
|
wcstring cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tokenizer;
|
struct tokenizer;
|
||||||
|
@ -390,11 +390,11 @@ class parser_t {
|
||||||
\param line Line to evaluate
|
\param line Line to evaluate
|
||||||
\param output List to insert output to
|
\param output List to insert output to
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
\param line Line to evaluate
|
\param line Line to evaluate
|
||||||
\param output List to insert output to
|
\param output List to insert output to
|
||||||
*/
|
*/
|
||||||
int eval_args( const wchar_t *line, std::vector<completion_t> &output );
|
int eval_args( const wchar_t *line, std::vector<completion_t> &output );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the current evaluation error. This function should only be used by libraries that are called by
|
Sets the current evaluation error. This function should only be used by libraries that are called by
|
||||||
|
|
|
@ -16,8 +16,8 @@ Functions having to do with parser keywords, like testing if a function is a blo
|
||||||
|
|
||||||
bool parser_keywords_is_switch( const wcstring &cmd )
|
bool parser_keywords_is_switch( const wcstring &cmd )
|
||||||
{
|
{
|
||||||
if (cmd == L"--") {
|
if (cmd == L"--") {
|
||||||
return ARG_SKIP;
|
return ARG_SKIP;
|
||||||
} else if (! cmd.empty() && cmd.at(0) == L'-') {
|
} else if (! cmd.empty() && cmd.at(0) == L'-') {
|
||||||
return ARG_SWITCH;
|
return ARG_SWITCH;
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,49 +27,49 @@ bool parser_keywords_is_switch( const wcstring &cmd )
|
||||||
|
|
||||||
bool parser_keywords_skip_arguments( const wcstring &cmd )
|
bool parser_keywords_skip_arguments( const wcstring &cmd )
|
||||||
{
|
{
|
||||||
return contains( cmd,
|
return contains( cmd,
|
||||||
L"else",
|
L"else",
|
||||||
L"begin" );
|
L"begin" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool parser_keywords_is_subcommand( const wcstring &cmd )
|
bool parser_keywords_is_subcommand( const wcstring &cmd )
|
||||||
{
|
{
|
||||||
|
|
||||||
return parser_keywords_skip_arguments( cmd ) ||
|
return parser_keywords_skip_arguments( cmd ) ||
|
||||||
contains( cmd,
|
contains( cmd,
|
||||||
L"command",
|
L"command",
|
||||||
L"builtin",
|
L"builtin",
|
||||||
L"while",
|
L"while",
|
||||||
L"exec",
|
L"exec",
|
||||||
L"if",
|
L"if",
|
||||||
L"and",
|
L"and",
|
||||||
L"or",
|
L"or",
|
||||||
L"not" );
|
L"not" );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_keywords_is_block( const wcstring &word)
|
bool parser_keywords_is_block( const wcstring &word)
|
||||||
{
|
{
|
||||||
return contains( word,
|
return contains( word,
|
||||||
L"for",
|
L"for",
|
||||||
L"while",
|
L"while",
|
||||||
L"if",
|
L"if",
|
||||||
L"function",
|
L"function",
|
||||||
L"switch",
|
L"switch",
|
||||||
L"begin" );
|
L"begin" );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_keywords_is_reserved( const wcstring &word)
|
bool parser_keywords_is_reserved( const wcstring &word)
|
||||||
{
|
{
|
||||||
return parser_keywords_is_block(word) ||
|
return parser_keywords_is_block(word) ||
|
||||||
parser_keywords_is_subcommand( word ) ||
|
parser_keywords_is_subcommand( word ) ||
|
||||||
contains( word,
|
contains( word,
|
||||||
L"end",
|
L"end",
|
||||||
L"case",
|
L"case",
|
||||||
L"else",
|
L"else",
|
||||||
L"return",
|
L"return",
|
||||||
L"continue",
|
L"continue",
|
||||||
L"break" );
|
L"break" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ Functions having to do with parser keywords, like testing if a function is a blo
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_NON_SWITCH,
|
ARG_NON_SWITCH,
|
||||||
ARG_SWITCH,
|
ARG_SWITCH,
|
||||||
ARG_SKIP
|
ARG_SKIP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
336
path.cpp
336
path.cpp
|
@ -25,110 +25,110 @@
|
||||||
|
|
||||||
static bool path_get_path_core(const wcstring &cmd, wcstring *out_path, const env_var_t &bin_path_var)
|
static bool path_get_path_core(const wcstring &cmd, wcstring *out_path, const env_var_t &bin_path_var)
|
||||||
{
|
{
|
||||||
int err = ENOENT;
|
int err = ENOENT;
|
||||||
|
|
||||||
debug( 3, L"path_get_path( '%ls' )", cmd.c_str() );
|
debug( 3, L"path_get_path( '%ls' )", cmd.c_str() );
|
||||||
|
|
||||||
/* If the command has a slash, it must be a full path */
|
/* If the command has a slash, it must be a full path */
|
||||||
if (cmd.find(L'/') != wcstring::npos)
|
if (cmd.find(L'/') != wcstring::npos)
|
||||||
{
|
{
|
||||||
if( waccess( cmd, X_OK )==0 )
|
if( waccess( cmd, X_OK )==0 )
|
||||||
{
|
{
|
||||||
struct stat buff;
|
struct stat buff;
|
||||||
if(wstat( cmd, &buff ))
|
if(wstat( cmd, &buff ))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( S_ISREG(buff.st_mode) )
|
if( S_ISREG(buff.st_mode) )
|
||||||
{
|
{
|
||||||
if (out_path)
|
if (out_path)
|
||||||
out_path->assign(cmd);
|
out_path->assign(cmd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct stat buff;
|
struct stat buff;
|
||||||
wstat( cmd, &buff );
|
wstat( cmd, &buff );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wcstring bin_path;
|
wcstring bin_path;
|
||||||
if (! bin_path_var.missing())
|
if (! bin_path_var.missing())
|
||||||
{
|
{
|
||||||
bin_path = bin_path_var;
|
bin_path = bin_path_var;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (contains( PREFIX L"/bin", L"/bin", L"/usr/bin" ))
|
if (contains( PREFIX L"/bin", L"/bin", L"/usr/bin" ))
|
||||||
{
|
{
|
||||||
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
|
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
|
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring nxt_path;
|
wcstring nxt_path;
|
||||||
wcstokenizer tokenizer(bin_path, ARRAY_SEP_STR);
|
wcstokenizer tokenizer(bin_path, ARRAY_SEP_STR);
|
||||||
while (tokenizer.next(nxt_path))
|
while (tokenizer.next(nxt_path))
|
||||||
{
|
{
|
||||||
if (nxt_path.empty())
|
if (nxt_path.empty())
|
||||||
continue;
|
continue;
|
||||||
append_path_component(nxt_path, cmd);
|
append_path_component(nxt_path, cmd);
|
||||||
if( waccess( nxt_path, X_OK )==0 )
|
if( waccess( nxt_path, X_OK )==0 )
|
||||||
{
|
{
|
||||||
struct stat buff;
|
struct stat buff;
|
||||||
if( wstat( nxt_path, &buff )==-1 )
|
if( wstat( nxt_path, &buff )==-1 )
|
||||||
{
|
{
|
||||||
if( errno != EACCES )
|
if( errno != EACCES )
|
||||||
{
|
{
|
||||||
wperror( L"stat" );
|
wperror( L"stat" );
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( S_ISREG(buff.st_mode) )
|
if( S_ISREG(buff.st_mode) )
|
||||||
{
|
{
|
||||||
if (out_path)
|
if (out_path)
|
||||||
out_path->swap(nxt_path);
|
out_path->swap(nxt_path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
err = EACCES;
|
err = EACCES;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch( errno )
|
switch( errno )
|
||||||
{
|
{
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
case ENAMETOOLONG:
|
case ENAMETOOLONG:
|
||||||
case EACCES:
|
case EACCES:
|
||||||
case ENOTDIR:
|
case ENOTDIR:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug( 1,
|
||||||
MISSING_COMMAND_ERR_MSG,
|
MISSING_COMMAND_ERR_MSG,
|
||||||
nxt_path.c_str() );
|
nxt_path.c_str() );
|
||||||
wperror( L"access" );
|
wperror( L"access" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = err;
|
errno = err;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path_get_path(const wcstring &cmd, wcstring *out_path, const env_vars_snapshot_t &vars)
|
bool path_get_path(const wcstring &cmd, wcstring *out_path, const env_vars_snapshot_t &vars)
|
||||||
|
@ -143,30 +143,30 @@ bool path_get_path(const wcstring &cmd, wcstring *out_path)
|
||||||
|
|
||||||
bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env_var_t &cdpath)
|
bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env_var_t &cdpath)
|
||||||
{
|
{
|
||||||
wchar_t *res = 0;
|
wchar_t *res = 0;
|
||||||
int err = ENOENT;
|
int err = ENOENT;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
const wchar_t *const dir = dir_str.c_str();
|
const wchar_t *const dir = dir_str.c_str();
|
||||||
if( dir[0] == L'/'|| (wcsncmp( dir, L"./", 2 )==0) )
|
if( dir[0] == L'/'|| (wcsncmp( dir, L"./", 2 )==0) )
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if( wstat( dir, &buf ) == 0 )
|
if( wstat( dir, &buf ) == 0 )
|
||||||
{
|
{
|
||||||
if( S_ISDIR(buf.st_mode) )
|
if( S_ISDIR(buf.st_mode) )
|
||||||
{
|
{
|
||||||
result = dir_str;
|
result = dir_str;
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = ENOTDIR;
|
err = ENOTDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
wcstring path = L".";
|
wcstring path = L".";
|
||||||
|
|
||||||
|
@ -186,44 +186,44 @@ bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env
|
||||||
wcstring whole_path = next_path;
|
wcstring whole_path = next_path;
|
||||||
append_path_component(whole_path, dir);
|
append_path_component(whole_path, dir);
|
||||||
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
if( wstat( whole_path, &buf ) == 0 )
|
if( wstat( whole_path, &buf ) == 0 )
|
||||||
{
|
{
|
||||||
if( S_ISDIR(buf.st_mode) )
|
if( S_ISDIR(buf.st_mode) )
|
||||||
{
|
{
|
||||||
result = whole_path;
|
result = whole_path;
|
||||||
success = true;
|
success = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = ENOTDIR;
|
err = ENOTDIR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( lwstat( whole_path, &buf ) == 0 )
|
if( lwstat( whole_path, &buf ) == 0 )
|
||||||
{
|
{
|
||||||
err = EROTTEN;
|
err = EROTTEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( !success )
|
if( !success )
|
||||||
{
|
{
|
||||||
errno = err;
|
errno = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, const env_vars_snapshot_t &env_vars)
|
bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, const env_vars_snapshot_t &env_vars)
|
||||||
{
|
{
|
||||||
int err = ENOENT;
|
int err = ENOENT;
|
||||||
if (dir.empty())
|
if (dir.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (wd)
|
if (wd)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +262,7 @@ bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, cons
|
||||||
}
|
}
|
||||||
expand_tilde(nxt_path);
|
expand_tilde(nxt_path);
|
||||||
|
|
||||||
// debug( 2, L"woot %ls\n", expanded_path.c_str() );
|
// debug( 2, L"woot %ls\n", expanded_path.c_str() );
|
||||||
|
|
||||||
if (nxt_path.empty())
|
if (nxt_path.empty())
|
||||||
continue;
|
continue;
|
||||||
|
@ -275,26 +275,26 @@ bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, cons
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter) {
|
for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter) {
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
const wcstring &dir = *iter;
|
const wcstring &dir = *iter;
|
||||||
if( wstat( dir, &buf ) == 0 )
|
if( wstat( dir, &buf ) == 0 )
|
||||||
{
|
{
|
||||||
if( S_ISDIR(buf.st_mode) )
|
if( S_ISDIR(buf.st_mode) )
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
if (out)
|
if (out)
|
||||||
out->assign(dir);
|
out->assign(dir);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = ENOTDIR;
|
err = ENOTDIR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! success)
|
if (! success)
|
||||||
errno = err;
|
errno = err;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,41 +317,41 @@ bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path, const wch
|
||||||
|
|
||||||
bool path_get_config(wcstring &path)
|
bool path_get_config(wcstring &path)
|
||||||
{
|
{
|
||||||
int done = 0;
|
int done = 0;
|
||||||
wcstring res;
|
wcstring res;
|
||||||
|
|
||||||
const env_var_t xdg_dir = env_get_string( L"XDG_CONFIG_HOME" );
|
const env_var_t xdg_dir = env_get_string( L"XDG_CONFIG_HOME" );
|
||||||
if( ! xdg_dir.missing() )
|
if( ! xdg_dir.missing() )
|
||||||
{
|
{
|
||||||
res = xdg_dir + L"/fish";
|
res = xdg_dir + L"/fish";
|
||||||
if( !create_directory( res ) )
|
if( !create_directory( res ) )
|
||||||
{
|
{
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const env_var_t home = env_get_string( L"HOME" );
|
const env_var_t home = env_get_string( L"HOME" );
|
||||||
if( ! home.missing() )
|
if( ! home.missing() )
|
||||||
{
|
{
|
||||||
res = home + L"/.config/fish";
|
res = home + L"/.config/fish";
|
||||||
if( !create_directory( res ) )
|
if( !create_directory( res ) )
|
||||||
{
|
{
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( done )
|
if( done )
|
||||||
{
|
{
|
||||||
path = res;
|
path = res;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug( 0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access." ));
|
debug( 0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access." ));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
path.h
8
path.h
|
@ -1,9 +1,9 @@
|
||||||
/** \file path.h
|
/** \file path.h
|
||||||
|
|
||||||
Directory utilities. This library contains functions for locating
|
Directory utilities. This library contains functions for locating
|
||||||
configuration directories, for testing if a command with a given
|
configuration directories, for testing if a command with a given
|
||||||
name can be found in the PATH, and various other path-related
|
name can be found in the PATH, and various other path-related
|
||||||
issues.
|
issues.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_PATH_H
|
#ifndef FISH_PATH_H
|
||||||
|
|
506
postfork.cpp
506
postfork.cpp
|
@ -1,6 +1,6 @@
|
||||||
/** \file postfork.cpp
|
/** \file postfork.cpp
|
||||||
|
|
||||||
Functions that we may safely call after fork().
|
Functions that we may safely call after fork().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -44,19 +44,19 @@ static void debug_safe_int(int level, const char *format, int val)
|
||||||
// PCA These calls to debug are rather sketchy because they may allocate memory. Fortunately they only occur if an error occurs.
|
// PCA These calls to debug are rather sketchy because they may allocate memory. Fortunately they only occur if an error occurs.
|
||||||
int set_child_group( job_t *j, process_t *p, int print_errors )
|
int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if( job_get_flag( j, JOB_CONTROL ) )
|
if( job_get_flag( j, JOB_CONTROL ) )
|
||||||
{
|
{
|
||||||
if (!j->pgid)
|
if (!j->pgid)
|
||||||
{
|
{
|
||||||
j->pgid = p->pid;
|
j->pgid = p->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( setpgid (p->pid, j->pgid) )
|
if( setpgid (p->pid, j->pgid) )
|
||||||
{
|
{
|
||||||
if( getpgid( p->pid) != j->pgid && print_errors )
|
if( getpgid( p->pid) != j->pgid && print_errors )
|
||||||
{
|
{
|
||||||
char pid_buff[128];
|
char pid_buff[128];
|
||||||
char job_id_buff[128];
|
char job_id_buff[128];
|
||||||
char getpgid_buff[128];
|
char getpgid_buff[128];
|
||||||
|
@ -67,38 +67,38 @@ int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||||
format_long_safe(getpgid_buff, getpgid( p->pid));
|
format_long_safe(getpgid_buff, getpgid( p->pid));
|
||||||
format_long_safe(job_pgid_buff, j->pgid);
|
format_long_safe(job_pgid_buff, j->pgid);
|
||||||
|
|
||||||
debug_safe( 1,
|
debug_safe( 1,
|
||||||
"Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
|
"Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
|
||||||
pid_buff,
|
pid_buff,
|
||||||
p->argv0_cstr(),
|
p->argv0_cstr(),
|
||||||
job_id_buff,
|
job_id_buff,
|
||||||
j->command_cstr(),
|
j->command_cstr(),
|
||||||
getpgid_buff,
|
getpgid_buff,
|
||||||
job_pgid_buff );
|
job_pgid_buff );
|
||||||
|
|
||||||
wperror( L"setpgid" );
|
wperror( L"setpgid" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
j->pgid = getpid();
|
j->pgid = getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
|
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
|
||||||
{
|
{
|
||||||
if( tcsetpgrp (0, j->pgid) && print_errors )
|
if( tcsetpgrp (0, j->pgid) && print_errors )
|
||||||
{
|
{
|
||||||
char job_id_buff[128];
|
char job_id_buff[128];
|
||||||
format_long_safe(job_id_buff, j->job_id);
|
format_long_safe(job_id_buff, j->job_id);
|
||||||
debug_safe( 1, "Could not send job %s ('%s') to foreground", job_id_buff, j->command_cstr() );
|
debug_safe( 1, "Could not send job %s ('%s') to foreground", job_id_buff, j->command_cstr() );
|
||||||
wperror( L"tcsetpgrp" );
|
wperror( L"tcsetpgrp" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make sure the fd used by each redirection is not used by a pipe. */
|
/** Make sure the fd used by each redirection is not used by a pipe. */
|
||||||
|
@ -143,7 +143,7 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
|
||||||
possible_conflict->param1.pipe_fd[k] = replacement_fd;
|
possible_conflict->param1.pipe_fd[k] = replacement_fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,149 +162,149 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
|
||||||
static int handle_child_io( io_chain_t &io_chain )
|
static int handle_child_io( io_chain_t &io_chain )
|
||||||
{
|
{
|
||||||
|
|
||||||
close_unused_internal_pipes( io_chain );
|
close_unused_internal_pipes( io_chain );
|
||||||
free_redirected_fds_from_pipes(io_chain);
|
free_redirected_fds_from_pipes(io_chain);
|
||||||
for (size_t idx = 0; idx < io_chain.size(); idx++)
|
for (size_t idx = 0; idx < io_chain.size(); idx++)
|
||||||
{
|
{
|
||||||
io_data_t *io = io_chain.at(idx);
|
io_data_t *io = io_chain.at(idx);
|
||||||
int tmp;
|
int tmp;
|
||||||
|
|
||||||
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
|
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( io->io_mode )
|
switch( io->io_mode )
|
||||||
{
|
{
|
||||||
case IO_CLOSE:
|
case IO_CLOSE:
|
||||||
{
|
{
|
||||||
if( close(io->fd) )
|
if( close(io->fd) )
|
||||||
{
|
{
|
||||||
debug_safe_int( 0, "Failed to close file descriptor %s", io->fd );
|
debug_safe_int( 0, "Failed to close file descriptor %s", io->fd );
|
||||||
wperror( L"close" );
|
wperror( L"close" );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_FILE:
|
case IO_FILE:
|
||||||
{
|
{
|
||||||
// Here we definitely do not want to set CLO_EXEC because our child needs access
|
// Here we definitely do not want to set CLO_EXEC because our child needs access
|
||||||
if( (tmp=open( io->filename_cstr,
|
if( (tmp=open( io->filename_cstr,
|
||||||
io->param2.flags, OPEN_MASK ) )==-1 )
|
io->param2.flags, OPEN_MASK ) )==-1 )
|
||||||
{
|
{
|
||||||
if( ( io->param2.flags & O_EXCL ) &&
|
if( ( io->param2.flags & O_EXCL ) &&
|
||||||
( errno ==EEXIST ) )
|
( errno ==EEXIST ) )
|
||||||
{
|
{
|
||||||
debug_safe( 1, NOCLOB_ERROR, io->filename_cstr );
|
debug_safe( 1, NOCLOB_ERROR, io->filename_cstr );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug_safe( 1, FILE_ERROR, io->filename_cstr );
|
debug_safe( 1, FILE_ERROR, io->filename_cstr );
|
||||||
perror( "open" );
|
perror( "open" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if( tmp != io->fd)
|
else if( tmp != io->fd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This call will sometimes fail, but that is ok,
|
This call will sometimes fail, but that is ok,
|
||||||
this is just a precausion.
|
this is just a precausion.
|
||||||
*/
|
*/
|
||||||
close(io->fd);
|
close(io->fd);
|
||||||
|
|
||||||
if(dup2( tmp, io->fd ) == -1 )
|
if(dup2( tmp, io->fd ) == -1 )
|
||||||
{
|
{
|
||||||
debug_safe_int( 1, FD_ERROR, io->fd );
|
debug_safe_int( 1, FD_ERROR, io->fd );
|
||||||
perror( "dup2" );
|
perror( "dup2" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
exec_close( tmp );
|
exec_close( tmp );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_FD:
|
case IO_FD:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This call will sometimes fail, but that is ok,
|
This call will sometimes fail, but that is ok,
|
||||||
this is just a precausion.
|
this is just a precausion.
|
||||||
*/
|
*/
|
||||||
close(io->fd);
|
close(io->fd);
|
||||||
|
|
||||||
if( dup2( io->param1.old_fd, io->fd ) == -1 )
|
if( dup2( io->param1.old_fd, io->fd ) == -1 )
|
||||||
{
|
{
|
||||||
debug_safe_int( 1, FD_ERROR, io->fd );
|
debug_safe_int( 1, FD_ERROR, io->fd );
|
||||||
wperror( L"dup2" );
|
wperror( L"dup2" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_BUFFER:
|
case IO_BUFFER:
|
||||||
case IO_PIPE:
|
case IO_PIPE:
|
||||||
{
|
{
|
||||||
/* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */
|
/* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */
|
||||||
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
||||||
/*
|
/*
|
||||||
debug( 0,
|
debug( 0,
|
||||||
L"%ls %ls on fd %d (%d %d)",
|
L"%ls %ls on fd %d (%d %d)",
|
||||||
write_pipe?L"write":L"read",
|
write_pipe?L"write":L"read",
|
||||||
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
|
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
|
||||||
io->fd,
|
io->fd,
|
||||||
io->param1.pipe_fd[0],
|
io->param1.pipe_fd[0],
|
||||||
io->param1.pipe_fd[1]);
|
io->param1.pipe_fd[1]);
|
||||||
*/
|
*/
|
||||||
if( dup2( io->param1.pipe_fd[write_pipe_idx], io->fd ) != io->fd )
|
if( dup2( io->param1.pipe_fd[write_pipe_idx], io->fd ) != io->fd )
|
||||||
{
|
{
|
||||||
debug_safe( 1, LOCAL_PIPE_ERROR );
|
debug_safe( 1, LOCAL_PIPE_ERROR );
|
||||||
perror( "dup2" );
|
perror( "dup2" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io->param1.pipe_fd[0] >= 0)
|
if (io->param1.pipe_fd[0] >= 0)
|
||||||
exec_close( io->param1.pipe_fd[0]);
|
exec_close( io->param1.pipe_fd[0]);
|
||||||
if (io->param1.pipe_fd[1] >= 0)
|
if (io->param1.pipe_fd[1] >= 0)
|
||||||
exec_close( io->param1.pipe_fd[1]);
|
exec_close( io->param1.pipe_fd[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int setup_child_process( job_t *j, process_t *p )
|
int setup_child_process( job_t *j, process_t *p )
|
||||||
{
|
{
|
||||||
bool ok=true;
|
bool ok=true;
|
||||||
|
|
||||||
if( p )
|
if( p )
|
||||||
{
|
{
|
||||||
ok = (0 == set_child_group( j, p, 1 ));
|
ok = (0 == set_child_group( j, p, 1 ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ok )
|
if( ok )
|
||||||
{
|
{
|
||||||
ok = (0 == handle_child_io( j->io ));
|
ok = (0 == handle_child_io( j->io ));
|
||||||
if( p != 0 && ! ok )
|
if( p != 0 && ! ok )
|
||||||
{
|
{
|
||||||
exit_without_destructors( 1 );
|
exit_without_destructors( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the handling for job control signals back to the default. */
|
/* Set the handling for job control signals back to the default. */
|
||||||
if( ok )
|
if( ok )
|
||||||
{
|
{
|
||||||
signal_reset_handlers();
|
signal_reset_handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all signal blocks */
|
/* Remove all signal blocks */
|
||||||
signal_unblock();
|
signal_unblock();
|
||||||
|
|
||||||
return ok ? 0 : -1;
|
return ok ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_fork_count = 0;
|
int g_fork_count = 0;
|
||||||
|
@ -324,41 +324,41 @@ pid_t execute_fork(bool wait_for_threads_to_die)
|
||||||
iothread_drain_all();
|
iothread_drain_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
struct timespec pollint;
|
struct timespec pollint;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
g_fork_count++;
|
g_fork_count++;
|
||||||
|
|
||||||
for( i=0; i<FORK_LAPS; i++ )
|
for( i=0; i<FORK_LAPS; i++ )
|
||||||
{
|
{
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if( pid >= 0)
|
if( pid >= 0)
|
||||||
{
|
{
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( errno != EAGAIN )
|
if( errno != EAGAIN )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pollint.tv_sec = 0;
|
pollint.tv_sec = 0;
|
||||||
pollint.tv_nsec = FORK_SLEEP_TIME;
|
pollint.tv_nsec = FORK_SLEEP_TIME;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Don't sleep on the final lap - sleeping might change the
|
Don't sleep on the final lap - sleeping might change the
|
||||||
value of errno, which will break the error reporting below.
|
value of errno, which will break the error reporting below.
|
||||||
*/
|
*/
|
||||||
if( i != FORK_LAPS-1 )
|
if( i != FORK_LAPS-1 )
|
||||||
{
|
{
|
||||||
nanosleep( &pollint, NULL );
|
nanosleep( &pollint, NULL );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_safe( 0, FORK_ERROR );
|
debug_safe( 0, FORK_ERROR );
|
||||||
wperror (L"fork");
|
wperror (L"fork");
|
||||||
FATAL_EXIT();
|
FATAL_EXIT();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,11 +389,11 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
desired_parent_group_id = j->pgid;
|
desired_parent_group_id = j->pgid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the handling for job control signals back to the default. */
|
/* Set the handling for job control signals back to the default. */
|
||||||
bool reset_signal_handlers = true;
|
bool reset_signal_handlers = true;
|
||||||
|
|
||||||
/* Remove all signal blocks */
|
/* Remove all signal blocks */
|
||||||
bool reset_sigmask = true;
|
bool reset_sigmask = true;
|
||||||
|
|
||||||
/* Set our flags */
|
/* Set our flags */
|
||||||
short flags = 0;
|
short flags = 0;
|
||||||
|
@ -440,17 +440,17 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
{
|
{
|
||||||
const io_data_t *io = j->io.at(idx);
|
const io_data_t *io = j->io.at(idx);
|
||||||
|
|
||||||
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
|
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( io->fd > 2 )
|
if( io->fd > 2 )
|
||||||
{
|
{
|
||||||
/* Make sure the fd used by this redirection is not used by e.g. a pipe. */
|
/* Make sure the fd used by this redirection is not used by e.g. a pipe. */
|
||||||
// free_fd(io_chain, io->fd );
|
// free_fd(io_chain, io->fd );
|
||||||
// PCA I don't think we need to worry about this. fd redirection is pretty uncommon anyways.
|
// PCA I don't think we need to worry about this. fd redirection is pretty uncommon anyways.
|
||||||
}
|
}
|
||||||
switch (io->io_mode)
|
switch (io->io_mode)
|
||||||
{
|
{
|
||||||
case IO_CLOSE:
|
case IO_CLOSE:
|
||||||
|
@ -474,9 +474,9 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_BUFFER:
|
case IO_BUFFER:
|
||||||
case IO_PIPE:
|
case IO_PIPE:
|
||||||
{
|
{
|
||||||
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
||||||
int from_fd = io->param1.pipe_fd[write_pipe_idx];
|
int from_fd = io->param1.pipe_fd[write_pipe_idx];
|
||||||
int to_fd = io->fd;
|
int to_fd = io->fd;
|
||||||
|
@ -484,19 +484,19 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
|
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
|
||||||
|
|
||||||
|
|
||||||
if( write_pipe_idx > 0 )
|
if( write_pipe_idx > 0 )
|
||||||
{
|
{
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[1]);
|
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,86 +514,86 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
|
|
||||||
void safe_report_exec_error(int err, const char *actual_cmd, char **argv, char **envv)
|
void safe_report_exec_error(int err, const char *actual_cmd, char **argv, char **envv)
|
||||||
{
|
{
|
||||||
debug_safe( 0, "Failed to execute process '%s'. Reason:", actual_cmd );
|
debug_safe( 0, "Failed to execute process '%s'. Reason:", actual_cmd );
|
||||||
|
|
||||||
switch( err )
|
switch( err )
|
||||||
{
|
{
|
||||||
|
|
||||||
case E2BIG:
|
case E2BIG:
|
||||||
{
|
{
|
||||||
char sz1[128], sz2[128];
|
char sz1[128], sz2[128];
|
||||||
|
|
||||||
long arg_max = -1;
|
long arg_max = -1;
|
||||||
|
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
char **p;
|
char **p;
|
||||||
for(p=argv; *p; p++)
|
for(p=argv; *p; p++)
|
||||||
{
|
{
|
||||||
sz += strlen(*p)+1;
|
sz += strlen(*p)+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(p=envv; *p; p++)
|
for(p=envv; *p; p++)
|
||||||
{
|
{
|
||||||
sz += strlen(*p)+1;
|
sz += strlen(*p)+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
format_size_safe(sz1, sz);
|
format_size_safe(sz1, sz);
|
||||||
arg_max = sysconf( _SC_ARG_MAX );
|
arg_max = sysconf( _SC_ARG_MAX );
|
||||||
|
|
||||||
if( arg_max > 0 )
|
if( arg_max > 0 )
|
||||||
{
|
{
|
||||||
format_size_safe(sz2, sz);
|
format_size_safe(sz2, sz);
|
||||||
debug_safe(0, "The total size of the argument and environment lists %s exceeds the operating system limit of %s.", sz1, sz2);
|
debug_safe(0, "The total size of the argument and environment lists %s exceeds the operating system limit of %s.", sz1, sz2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug_safe( 0, "The total size of the argument and environment lists (%s) exceeds the operating system limit.", sz1);
|
debug_safe( 0, "The total size of the argument and environment lists (%s) exceeds the operating system limit.", sz1);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_safe(0, "Try running the command again with fewer arguments.");
|
debug_safe(0, "Try running the command again with fewer arguments.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ENOEXEC:
|
case ENOEXEC:
|
||||||
{
|
{
|
||||||
/* Hope strerror doesn't allocate... */
|
/* Hope strerror doesn't allocate... */
|
||||||
const char *err = strerror(errno);
|
const char *err = strerror(errno);
|
||||||
debug_safe(0, "exec: %s", err);
|
debug_safe(0, "exec: %s", err);
|
||||||
|
|
||||||
debug_safe(0, "The file '%s' is marked as an executable but could not be run by the operating system.", actual_cmd);
|
debug_safe(0, "The file '%s' is marked as an executable but could not be run by the operating system.", actual_cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
{
|
{
|
||||||
/* ENOENT is returned by exec() when the path fails, but also returned by posix_spawn if an open file action fails. These cases appear to be impossible to distinguish. We address this by not using posix_spawn for file redirections, so all the ENOENTs we find must be errors from exec(). */
|
/* ENOENT is returned by exec() when the path fails, but also returned by posix_spawn if an open file action fails. These cases appear to be impossible to distinguish. We address this by not using posix_spawn for file redirections, so all the ENOENTs we find must be errors from exec(). */
|
||||||
char interpreter_buff[128] = {}, *interpreter;
|
char interpreter_buff[128] = {}, *interpreter;
|
||||||
interpreter = get_interpreter(actual_cmd, interpreter_buff, sizeof interpreter_buff);
|
interpreter = get_interpreter(actual_cmd, interpreter_buff, sizeof interpreter_buff);
|
||||||
if( interpreter && 0 != access( interpreter, X_OK ) )
|
if( interpreter && 0 != access( interpreter, X_OK ) )
|
||||||
{
|
{
|
||||||
debug_safe(0, "The file '%s' specified the interpreter '%s', which is not an executable command.", actual_cmd, interpreter );
|
debug_safe(0, "The file '%s' specified the interpreter '%s', which is not an executable command.", actual_cmd, interpreter );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug_safe(0, "The file '%s' does not exist or could not be executed.", actual_cmd);
|
debug_safe(0, "The file '%s' does not exist or could not be executed.", actual_cmd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ENOMEM:
|
case ENOMEM:
|
||||||
{
|
{
|
||||||
debug_safe(0, "Out of memory");
|
debug_safe(0, "Out of memory");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
/* Hope strerror doesn't allocate... */
|
/* Hope strerror doesn't allocate... */
|
||||||
const char *err = strerror(errno);
|
const char *err = strerror(errno);
|
||||||
debug_safe(0, "exec: %s", err);
|
debug_safe(0, "exec: %s", err);
|
||||||
|
|
||||||
// debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
|
// debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** \file postfork.h
|
/** \file postfork.h
|
||||||
|
|
||||||
Functions that we may safely call after fork(), of which there are very few. In particular we cannot allocate memory, since we're insane enough to call fork from a multithreaded process.
|
Functions that we may safely call after fork(), of which there are very few. In particular we cannot allocate memory, since we're insane enough to call fork from a multithreaded process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_POSTFORK_H
|
#ifndef FISH_POSTFORK_H
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
/** \file print_help.c
|
/** \file print_help.c
|
||||||
Print help message for the specified command
|
Print help message for the specified command
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -19,16 +19,16 @@ ssize_t write_loop(int fd, const char *buff, size_t count);
|
||||||
|
|
||||||
void print_help( const char *c, int fd )
|
void print_help( const char *c, int fd )
|
||||||
{
|
{
|
||||||
char cmd[ CMD_LEN];
|
char cmd[ CMD_LEN];
|
||||||
int printed = snprintf( cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd );
|
int printed = snprintf( cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd );
|
||||||
|
|
||||||
if( printed < CMD_LEN )
|
if( printed < CMD_LEN )
|
||||||
{
|
{
|
||||||
if( (system( cmd ) == -1) )
|
if( (system( cmd ) == -1) )
|
||||||
{
|
{
|
||||||
write_loop(2, HELP_ERR, strlen(HELP_ERR));
|
write_loop(2, HELP_ERR, strlen(HELP_ERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
|
||||||
/** \file print_help.h
|
/** \file print_help.h
|
||||||
Print help message for the specified command
|
Print help message for the specified command
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_PRINT_HELP_H
|
#ifndef FISH_PRINT_HELP_H
|
||||||
#define FISH_PRINT_HELP_H
|
#define FISH_PRINT_HELP_H
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Print help message for the specified command
|
Print help message for the specified command
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void print_help( const char *cmd, int fd );
|
void print_help( const char *cmd, int fd );
|
||||||
|
|
260
proc.h
260
proc.h
|
@ -1,10 +1,10 @@
|
||||||
/** \file proc.h
|
/** \file proc.h
|
||||||
|
|
||||||
Prototypes for utilities for keeping track of jobs, processes and subshells, as
|
Prototypes for utilities for keeping track of jobs, processes and subshells, as
|
||||||
well as signal handling functions for tracking children. These
|
well as signal handling functions for tracking children. These
|
||||||
functions do not themselves launch new processes, the exec library
|
functions do not themselves launch new processes, the exec library
|
||||||
will call proc to create representations of the running jobs as
|
will call proc to create representations of the running jobs as
|
||||||
needed.
|
needed.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -56,73 +56,73 @@
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
A regular external command
|
A regular external command
|
||||||
*/
|
*/
|
||||||
EXTERNAL,
|
EXTERNAL,
|
||||||
/**
|
/**
|
||||||
A builtin command
|
A builtin command
|
||||||
*/
|
*/
|
||||||
INTERNAL_BUILTIN,
|
INTERNAL_BUILTIN,
|
||||||
/**
|
/**
|
||||||
A shellscript function
|
A shellscript function
|
||||||
*/
|
*/
|
||||||
INTERNAL_FUNCTION,
|
INTERNAL_FUNCTION,
|
||||||
/**
|
/**
|
||||||
A block of commands
|
A block of commands
|
||||||
*/
|
*/
|
||||||
INTERNAL_BLOCK,
|
INTERNAL_BLOCK,
|
||||||
/**
|
/**
|
||||||
The exec builtin
|
The exec builtin
|
||||||
*/
|
*/
|
||||||
INTERNAL_EXEC,
|
INTERNAL_EXEC,
|
||||||
/**
|
/**
|
||||||
A buffer
|
A buffer
|
||||||
*/
|
*/
|
||||||
INTERNAL_BUFFER,
|
INTERNAL_BUFFER,
|
||||||
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
JOB_CONTROL_ALL,
|
JOB_CONTROL_ALL,
|
||||||
JOB_CONTROL_INTERACTIVE,
|
JOB_CONTROL_INTERACTIVE,
|
||||||
JOB_CONTROL_NONE,
|
JOB_CONTROL_NONE,
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A structure representing a single fish process. Contains variables
|
A structure representing a single fish process. Contains variables
|
||||||
for tracking process state and the process argument
|
for tracking process state and the process argument
|
||||||
list. Actually, a fish process can be either a regular externa
|
list. Actually, a fish process can be either a regular externa
|
||||||
lrocess, an internal builtin which may or may not spawn a fake IO
|
lrocess, an internal builtin which may or may not spawn a fake IO
|
||||||
process during execution, a shellscript function or a block of
|
process during execution, a shellscript function or a block of
|
||||||
commands to be evaluated by calling eval. Lastly, this process can
|
commands to be evaluated by calling eval. Lastly, this process can
|
||||||
be the result of an exec command. The role of this process_t is
|
be the result of an exec command. The role of this process_t is
|
||||||
determined by the type field, which can be one of EXTERNAL,
|
determined by the type field, which can be one of EXTERNAL,
|
||||||
INTERNAL_BUILTIN, INTERNAL_FUNCTION, INTERNAL_BLOCK and
|
INTERNAL_BUILTIN, INTERNAL_FUNCTION, INTERNAL_BLOCK and
|
||||||
INTERNAL_EXEC, INTERNAL_BUFFER
|
INTERNAL_EXEC, INTERNAL_BUFFER
|
||||||
|
|
||||||
The process_t contains information on how the process should be
|
The process_t contains information on how the process should be
|
||||||
started, such as command name and arguments, as well as runtime
|
started, such as command name and arguments, as well as runtime
|
||||||
information on the status of the actual physical process which
|
information on the status of the actual physical process which
|
||||||
represents it. Shellscript functions, builtins and blocks of code
|
represents it. Shellscript functions, builtins and blocks of code
|
||||||
may all need to spawn an external process that handles the piping
|
may all need to spawn an external process that handles the piping
|
||||||
and redirecting of IO for them.
|
and redirecting of IO for them.
|
||||||
|
|
||||||
If the process is of type EXTERNAL or INTERNAL_EXEC, argv is the
|
If the process is of type EXTERNAL or INTERNAL_EXEC, argv is the
|
||||||
argument array and actual_cmd is the absolute path of the command
|
argument array and actual_cmd is the absolute path of the command
|
||||||
to execute.
|
to execute.
|
||||||
|
|
||||||
If the process is of type INTERNAL_BUILTIN, argv is the argument
|
If the process is of type INTERNAL_BUILTIN, argv is the argument
|
||||||
vector, and argv[0] is the name of the builtin command.
|
vector, and argv[0] is the name of the builtin command.
|
||||||
|
|
||||||
If the process is of type INTERNAL_FUNCTION, argv is the argument
|
If the process is of type INTERNAL_FUNCTION, argv is the argument
|
||||||
vector, and argv[0] is the name of the shellscript function.
|
vector, and argv[0] is the name of the shellscript function.
|
||||||
|
|
||||||
If the process is of type INTERNAL_BLOCK, argv has exactly one
|
If the process is of type INTERNAL_BLOCK, argv has exactly one
|
||||||
element, which is the block of commands to execute.
|
element, which is the block of commands to execute.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class process_t
|
class process_t
|
||||||
|
@ -144,12 +144,12 @@ class process_t
|
||||||
|
|
||||||
~process_t();
|
~process_t();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Type of process. Can be one of \c EXTERNAL, \c
|
Type of process. Can be one of \c EXTERNAL, \c
|
||||||
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK,
|
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK,
|
||||||
INTERNAL_EXEC, or INTERNAL_BUFFER
|
INTERNAL_EXEC, or INTERNAL_BUFFER
|
||||||
*/
|
*/
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
|
||||||
/** Sets argv */
|
/** Sets argv */
|
||||||
|
@ -180,41 +180,41 @@ class process_t
|
||||||
return argv0_narrow.get();
|
return argv0_narrow.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. */
|
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. */
|
||||||
wcstring actual_cmd;
|
wcstring actual_cmd;
|
||||||
|
|
||||||
/** process ID */
|
/** process ID */
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
/** File descriptor that pipe output should bind to */
|
/** File descriptor that pipe output should bind to */
|
||||||
int pipe_write_fd;
|
int pipe_write_fd;
|
||||||
|
|
||||||
/** File descriptor that the _next_ process pipe input should bind to */
|
/** File descriptor that the _next_ process pipe input should bind to */
|
||||||
int pipe_read_fd;
|
int pipe_read_fd;
|
||||||
|
|
||||||
/** true if process has completed */
|
/** true if process has completed */
|
||||||
volatile int completed;
|
volatile int completed;
|
||||||
|
|
||||||
/** true if process has stopped */
|
/** true if process has stopped */
|
||||||
volatile int stopped;
|
volatile int stopped;
|
||||||
|
|
||||||
/** reported status value */
|
/** reported status value */
|
||||||
volatile int status;
|
volatile int status;
|
||||||
|
|
||||||
/** Special flag to tell the evaluation function for count to print the help information */
|
/** Special flag to tell the evaluation function for count to print the help information */
|
||||||
int count_help_magic;
|
int count_help_magic;
|
||||||
|
|
||||||
/** Next process in pipeline. We own this and we are responsible for deleting it. */
|
/** Next process in pipeline. We own this and we are responsible for deleting it. */
|
||||||
process_t *next;
|
process_t *next;
|
||||||
#ifdef HAVE__PROC_SELF_STAT
|
#ifdef HAVE__PROC_SELF_STAT
|
||||||
/** Last time of cpu time check */
|
/** Last time of cpu time check */
|
||||||
struct timeval last_time;
|
struct timeval last_time;
|
||||||
/** Number of jiffies spent in process at last cpu time check */
|
/** Number of jiffies spent in process at last cpu time check */
|
||||||
unsigned long last_jiffies;
|
unsigned long last_jiffies;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Constants for the flag variable in the job struct */
|
/* Constants for the flag variable in the job struct */
|
||||||
enum {
|
enum {
|
||||||
/** true if user was told about stopped job */
|
/** true if user was told about stopped job */
|
||||||
JOB_NOTIFIED = 1 << 0,
|
JOB_NOTIFIED = 1 << 0,
|
||||||
|
@ -223,9 +223,9 @@ enum {
|
||||||
JOB_FOREGROUND = 1 << 1,
|
JOB_FOREGROUND = 1 << 1,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether the specified job is completely constructed,
|
Whether the specified job is completely constructed,
|
||||||
i.e. completely parsed, and every process in the job has been
|
i.e. completely parsed, and every process in the job has been
|
||||||
forked, etc.
|
forked, etc.
|
||||||
*/
|
*/
|
||||||
JOB_CONSTRUCTED = 1 << 2,
|
JOB_CONSTRUCTED = 1 << 2,
|
||||||
|
|
||||||
|
@ -261,12 +261,12 @@ void release_job_id(job_id_t jobid);
|
||||||
|
|
||||||
class job_t
|
class job_t
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
The original command which led to the creation of this
|
The original command which led to the creation of this
|
||||||
job. It is used for displaying messages about job status
|
job. It is used for displaying messages about job status
|
||||||
on the terminal.
|
on the terminal.
|
||||||
*/
|
*/
|
||||||
wcstring command_str;
|
wcstring command_str;
|
||||||
|
|
||||||
/* narrow copy so we don't have to convert after fork */
|
/* narrow copy so we don't have to convert after fork */
|
||||||
narrow_string_rep_t command_narrow;
|
narrow_string_rep_t command_narrow;
|
||||||
|
@ -298,68 +298,68 @@ class job_t
|
||||||
command_narrow.set(cmd);
|
command_narrow.set(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A linked list of all the processes in this job. We are responsible for deleting this when we are deallocated.
|
A linked list of all the processes in this job. We are responsible for deleting this when we are deallocated.
|
||||||
*/
|
*/
|
||||||
process_t *first_process;
|
process_t *first_process;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
process group ID for the process group that this job is
|
process group ID for the process group that this job is
|
||||||
running in.
|
running in.
|
||||||
*/
|
*/
|
||||||
pid_t pgid;
|
pid_t pgid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The saved terminal modes of this job. This needs to be
|
The saved terminal modes of this job. This needs to be
|
||||||
saved so that we can restore the terminal to the same
|
saved so that we can restore the terminal to the same
|
||||||
state after temporarily taking control over the terminal
|
state after temporarily taking control over the terminal
|
||||||
when a job stops.
|
when a job stops.
|
||||||
*/
|
*/
|
||||||
struct termios tmodes;
|
struct termios tmodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The job id of the job. This is a small integer that is a
|
The job id of the job. This is a small integer that is a
|
||||||
unique identifier of the job within this shell, and is
|
unique identifier of the job within this shell, and is
|
||||||
used e.g. in process expansion.
|
used e.g. in process expansion.
|
||||||
*/
|
*/
|
||||||
const job_id_t job_id;
|
const job_id_t job_id;
|
||||||
|
|
||||||
/** List of all IO redirections for this job. */
|
/** List of all IO redirections for this job. */
|
||||||
io_chain_t io;
|
io_chain_t io;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Bitset containing information about the job. A combination of the JOB_* constants.
|
Bitset containing information about the job. A combination of the JOB_* constants.
|
||||||
*/
|
*/
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether we are running a subshell command
|
Whether we are running a subshell command
|
||||||
*/
|
*/
|
||||||
extern int is_subshell;
|
extern int is_subshell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether we are running a block of commands
|
Whether we are running a block of commands
|
||||||
*/
|
*/
|
||||||
extern int is_block;
|
extern int is_block;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether we are reading from the keyboard right now
|
Whether we are reading from the keyboard right now
|
||||||
*/
|
*/
|
||||||
int get_is_interactive(void);
|
int get_is_interactive(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether this shell is attached to the keyboard at all
|
Whether this shell is attached to the keyboard at all
|
||||||
*/
|
*/
|
||||||
extern int is_interactive_session;
|
extern int is_interactive_session;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether we are a login shell
|
Whether we are a login shell
|
||||||
*/
|
*/
|
||||||
extern int is_login;
|
extern int is_login;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Whether we are running an event handler
|
Whether we are running an event handler
|
||||||
*/
|
*/
|
||||||
extern int is_event;
|
extern int is_event;
|
||||||
|
|
||||||
|
|
3018
reader.cpp
3018
reader.cpp
File diff suppressed because it is too large
Load diff
6
reader.h
6
reader.h
|
@ -1,9 +1,9 @@
|
||||||
/** \file reader.h
|
/** \file reader.h
|
||||||
|
|
||||||
Prototypes for functions for reading data from stdin and passing
|
Prototypes for functions for reading data from stdin and passing
|
||||||
to the parser. If stdin is a keyboard, it supplies a killring,
|
to the parser. If stdin is a keyboard, it supplies a killring,
|
||||||
history, syntax highlighting, tab-completion and various other
|
history, syntax highlighting, tab-completion and various other
|
||||||
features.
|
features.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_READER_H
|
#ifndef FISH_READER_H
|
||||||
|
|
52
sanity.cpp
52
sanity.cpp
|
@ -1,5 +1,5 @@
|
||||||
/** \file sanity.c
|
/** \file sanity.c
|
||||||
Functions for performing sanity checks on the program state
|
Functions for performing sanity checks on the program state
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -34,43 +34,43 @@ static int insane;
|
||||||
|
|
||||||
void sanity_lose()
|
void sanity_lose()
|
||||||
{
|
{
|
||||||
debug( 0, _(L"Errors detected, shutting down. Break on sanity_lose() to debug.") );
|
debug( 0, _(L"Errors detected, shutting down. Break on sanity_lose() to debug.") );
|
||||||
insane = 1;
|
insane = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sanity_check()
|
int sanity_check()
|
||||||
{
|
{
|
||||||
if( !insane )
|
if( !insane )
|
||||||
if( get_is_interactive() )
|
if( get_is_interactive() )
|
||||||
history_sanity_check();
|
history_sanity_check();
|
||||||
if( !insane )
|
if( !insane )
|
||||||
reader_sanity_check();
|
reader_sanity_check();
|
||||||
if( !insane )
|
if( !insane )
|
||||||
kill_sanity_check();
|
kill_sanity_check();
|
||||||
if( !insane )
|
if( !insane )
|
||||||
proc_sanity_check();
|
proc_sanity_check();
|
||||||
|
|
||||||
return insane;
|
return insane;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_pointer( const void *ptr, const wchar_t *err, int null_ok )
|
void validate_pointer( const void *ptr, const wchar_t *err, int null_ok )
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test if the pointer data crosses a segment boundary.
|
Test if the pointer data crosses a segment boundary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( (0x00000003l & (intptr_t)ptr) != 0 )
|
if( (0x00000003l & (intptr_t)ptr) != 0 )
|
||||||
{
|
{
|
||||||
debug( 0, _(L"The pointer '%ls' is invalid"), err );
|
debug( 0, _(L"The pointer '%ls' is invalid"), err );
|
||||||
sanity_lose();
|
sanity_lose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((!null_ok) && (ptr==0))
|
if((!null_ok) && (ptr==0))
|
||||||
{
|
{
|
||||||
debug( 0, _(L"The pointer '%ls' is null"), err );
|
debug( 0, _(L"The pointer '%ls' is null"), err );
|
||||||
sanity_lose();
|
sanity_lose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
2
sanity.h
2
sanity.h
|
@ -1,5 +1,5 @@
|
||||||
/** \file sanity.h
|
/** \file sanity.h
|
||||||
Prototypes for functions for performing sanity checks on the program state
|
Prototypes for functions for performing sanity checks on the program state
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_SANITY_H
|
#ifndef FISH_SANITY_H
|
||||||
|
|
884
screen.cpp
884
screen.cpp
File diff suppressed because it is too large
Load diff
50
screen.h
50
screen.h
|
@ -1,13 +1,13 @@
|
||||||
/** \file screen.h High level library for handling the terminal screen
|
/** \file screen.h High level library for handling the terminal screen
|
||||||
|
|
||||||
The screen library allows the interactive reader to write its
|
The screen library allows the interactive reader to write its
|
||||||
output to screen efficiently by keeping an inetrnal representation
|
output to screen efficiently by keeping an inetrnal representation
|
||||||
of the current screen contents and trying to find a reasonably
|
of the current screen contents and trying to find a reasonably
|
||||||
efficient way for transforming that to the desired screen content.
|
efficient way for transforming that to the desired screen content.
|
||||||
|
|
||||||
The current implementation is less smart than ncurses allows
|
The current implementation is less smart than ncurses allows
|
||||||
and can not for example move blocks of text around to handle text
|
and can not for example move blocks of text around to handle text
|
||||||
insertion.
|
insertion.
|
||||||
*/
|
*/
|
||||||
#ifndef FISH_SCREEN_H
|
#ifndef FISH_SCREEN_H
|
||||||
#define FISH_SCREEN_H
|
#define FISH_SCREEN_H
|
||||||
|
@ -135,21 +135,21 @@ class screen_t
|
||||||
screen_data_t::cursor_t soft_wrap_location;
|
screen_data_t::cursor_t soft_wrap_location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This flag is set to true when there is reason to suspect that
|
This flag is set to true when there is reason to suspect that
|
||||||
the parts of the screen lines where the actual content is not
|
the parts of the screen lines where the actual content is not
|
||||||
filled in may be non-empty. This means that a clr_eol command
|
filled in may be non-empty. This means that a clr_eol command
|
||||||
has to be sent to the terminal at the end of each line.
|
has to be sent to the terminal at the end of each line.
|
||||||
*/
|
*/
|
||||||
bool need_clear;
|
bool need_clear;
|
||||||
|
|
||||||
/** If we need to clear, this is how many lines the actual screen had, before we reset it. This is used when resizing the window larger: if the cursor jumps to the line above, we need to remember to clear the subsequent lines. */
|
/** If we need to clear, this is how many lines the actual screen had, before we reset it. This is used when resizing the window larger: if the cursor jumps to the line above, we need to remember to clear the subsequent lines. */
|
||||||
size_t actual_lines_before_reset;
|
size_t actual_lines_before_reset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
These status buffers are used to check if any output has occurred
|
These status buffers are used to check if any output has occurred
|
||||||
other than from fish's main loop, in which case we need to redraw.
|
other than from fish's main loop, in which case we need to redraw.
|
||||||
*/
|
*/
|
||||||
struct stat prev_buff_1, prev_buff_2, post_buff_1, post_buff_2;
|
struct stat prev_buff_1, prev_buff_2, post_buff_1, post_buff_2;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,13 +169,13 @@ class screen_t
|
||||||
\param cursor_pos where the cursor is
|
\param cursor_pos where the cursor is
|
||||||
*/
|
*/
|
||||||
void s_write( screen_t *s,
|
void s_write( screen_t *s,
|
||||||
const wchar_t *left_prompt,
|
const wchar_t *left_prompt,
|
||||||
const wchar_t *right_prompt,
|
const wchar_t *right_prompt,
|
||||||
const wchar_t *commandline,
|
const wchar_t *commandline,
|
||||||
size_t explicit_len,
|
size_t explicit_len,
|
||||||
const int *colors,
|
const int *colors,
|
||||||
const int *indent,
|
const int *indent,
|
||||||
size_t cursor_pos );
|
size_t cursor_pos );
|
||||||
|
|
||||||
|
|
||||||
void s_write( screen_t *s,
|
void s_write( screen_t *s,
|
||||||
|
|
356
set_color.cpp
356
set_color.cpp
|
@ -70,53 +70,53 @@
|
||||||
|
|
||||||
const char *col[]=
|
const char *col[]=
|
||||||
{
|
{
|
||||||
"black",
|
"black",
|
||||||
"red",
|
"red",
|
||||||
"green",
|
"green",
|
||||||
"brown",
|
"brown",
|
||||||
"yellow",
|
"yellow",
|
||||||
"blue",
|
"blue",
|
||||||
"magenta",
|
"magenta",
|
||||||
"purple",
|
"purple",
|
||||||
"cyan",
|
"cyan",
|
||||||
"white",
|
"white",
|
||||||
"normal"
|
"normal"
|
||||||
};
|
};
|
||||||
|
|
||||||
const int col_idx[]=
|
const int col_idx[]=
|
||||||
{
|
{
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
3,
|
3,
|
||||||
4,
|
4,
|
||||||
5,
|
5,
|
||||||
5,
|
5,
|
||||||
6,
|
6,
|
||||||
7,
|
7,
|
||||||
8
|
8
|
||||||
};
|
};
|
||||||
|
|
||||||
void print_colors()
|
void print_colors()
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
for( i=0; i<COLORS; i++ )
|
for( i=0; i<COLORS; i++ )
|
||||||
{
|
{
|
||||||
printf( "%s\n", col[i] );
|
printf( "%s\n", col[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_locale_init()
|
static void check_locale_init()
|
||||||
{
|
{
|
||||||
static int is_init = 0;
|
static int is_init = 0;
|
||||||
if( is_init )
|
if( is_init )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
is_init = 1;
|
is_init = 1;
|
||||||
setlocale( LC_ALL, "" );
|
setlocale( LC_ALL, "" );
|
||||||
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
||||||
textdomain( PACKAGE_NAME );
|
textdomain( PACKAGE_NAME );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A lot of this code is taken straight from output.cpp; it sure would be nice to factor these together. */
|
/* A lot of this code is taken straight from output.cpp; it sure would be nice to factor these together. */
|
||||||
|
@ -186,109 +186,109 @@ int main( int argc, char **argv )
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
char *bgcolor=0;
|
char *bgcolor=0;
|
||||||
char *fgcolor=0;
|
char *fgcolor=0;
|
||||||
bool bold=false;
|
bool bold=false;
|
||||||
bool underline=false;
|
bool underline=false;
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
static struct option
|
static struct option
|
||||||
long_options[] =
|
long_options[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"background", required_argument, 0, 'b'
|
"background", required_argument, 0, 'b'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"help", no_argument, 0, 'h'
|
"help", no_argument, 0, 'h'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"bold", no_argument, 0, 'o'
|
"bold", no_argument, 0, 'o'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"underline", no_argument, 0, 'u'
|
"underline", no_argument, 0, 'u'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"version", no_argument, 0, 'v'
|
"version", no_argument, 0, 'v'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
"print-colors", no_argument, 0, 'c'
|
"print-colors", no_argument, 0, 'c'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
|
|
||||||
int opt = getopt_long( argc,
|
int opt = getopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
GETOPT_STRING,
|
GETOPT_STRING,
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
|
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch( opt )
|
switch( opt )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b':
|
case 'b':
|
||||||
bgcolor = optarg;
|
bgcolor = optarg;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help( argv[0], 1 );
|
print_help( argv[0], 1 );
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
bold=true;
|
bold=true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
underline=true;
|
underline=true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
check_locale_init();
|
check_locale_init();
|
||||||
fprintf( stderr, _("%s, version %s\n"), SET_COLOR, PACKAGE_VERSION );
|
fprintf( stderr, _("%s, version %s\n"), SET_COLOR, PACKAGE_VERSION );
|
||||||
exit( 0 );
|
exit( 0 );
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
print_colors();
|
print_colors();
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( argc-optind)
|
switch( argc-optind)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// printf( "no fg\n" );
|
// printf( "no fg\n" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
fgcolor=argv[optind];
|
fgcolor=argv[optind];
|
||||||
// printf( "fg %s\n", fgcolor );
|
// printf( "fg %s\n", fgcolor );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
check_locale_init();
|
check_locale_init();
|
||||||
printf( _("%s: Too many arguments\n"), SET_COLOR );
|
printf( _("%s: Too many arguments\n"), SET_COLOR );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Infer term256 support */
|
/* Infer term256 support */
|
||||||
char *fish_term256 = getenv("fish_term256");
|
char *fish_term256 = getenv("fish_term256");
|
||||||
|
@ -299,77 +299,77 @@ int main( int argc, char **argv )
|
||||||
support_term256 = term && strstr(term, "256color");
|
support_term256 = term && strstr(term, "256color");
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !fgcolor && !bgcolor && !bold && !underline )
|
if( !fgcolor && !bgcolor && !bold && !underline )
|
||||||
{
|
{
|
||||||
check_locale_init();
|
check_locale_init();
|
||||||
fprintf( stderr, _("%s: Expected an argument\n"), SET_COLOR );
|
fprintf( stderr, _("%s: Expected an argument\n"), SET_COLOR );
|
||||||
print_help( argv[0], 2 );
|
print_help( argv[0], 2 );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : "");
|
rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : "");
|
||||||
if( fgcolor && fg.is_none())
|
if( fgcolor && fg.is_none())
|
||||||
{
|
{
|
||||||
check_locale_init();
|
check_locale_init();
|
||||||
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, fgcolor );
|
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, fgcolor );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : "");
|
rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : "");
|
||||||
if( bgcolor && bg.is_none())
|
if( bgcolor && bg.is_none())
|
||||||
{
|
{
|
||||||
check_locale_init();
|
check_locale_init();
|
||||||
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, bgcolor );
|
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, bgcolor );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupterm( 0, STDOUT_FILENO, 0);
|
setupterm( 0, STDOUT_FILENO, 0);
|
||||||
|
|
||||||
if( bold )
|
if( bold )
|
||||||
{
|
{
|
||||||
if( enter_bold_mode )
|
if( enter_bold_mode )
|
||||||
putp( enter_bold_mode );
|
putp( enter_bold_mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( underline )
|
if( underline )
|
||||||
{
|
{
|
||||||
if( enter_underline_mode )
|
if( enter_underline_mode )
|
||||||
putp( enter_underline_mode );
|
putp( enter_underline_mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bgcolor )
|
if( bgcolor )
|
||||||
{
|
{
|
||||||
if( bg.is_normal() )
|
if( bg.is_normal() )
|
||||||
{
|
{
|
||||||
write_background_color(0);
|
write_background_color(0);
|
||||||
putp( tparm(exit_attribute_mode) );
|
putp( tparm(exit_attribute_mode) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fgcolor )
|
if( fgcolor )
|
||||||
{
|
{
|
||||||
if( fg.is_normal() )
|
if( fg.is_normal() )
|
||||||
{
|
{
|
||||||
write_foreground_color(0);
|
write_foreground_color(0);
|
||||||
putp( tparm(exit_attribute_mode) );
|
putp( tparm(exit_attribute_mode) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_foreground_color(index_for_color(fg));
|
write_foreground_color(index_for_color(fg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( bgcolor )
|
if( bgcolor )
|
||||||
{
|
{
|
||||||
if( ! bg.is_normal() )
|
if( ! bg.is_normal() )
|
||||||
{
|
{
|
||||||
write_background_color(index_for_color(bg));
|
write_background_color(index_for_color(bg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( del_curterm( cur_term ) == ERR )
|
if( del_curterm( cur_term ) == ERR )
|
||||||
{
|
{
|
||||||
fprintf( stderr, "%s", _("Error while closing terminfo") );
|
fprintf( stderr, "%s", _("Error while closing terminfo") );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
848
signal.cpp
848
signal.cpp
File diff suppressed because it is too large
Load diff
916
tokenizer.cpp
916
tokenizer.cpp
File diff suppressed because it is too large
Load diff
80
tokenizer.h
80
tokenizer.h
|
@ -16,19 +16,19 @@
|
||||||
*/
|
*/
|
||||||
enum token_type
|
enum token_type
|
||||||
{
|
{
|
||||||
TOK_NONE, /**< Tokenizer not yet constructed */
|
TOK_NONE, /**< Tokenizer not yet constructed */
|
||||||
TOK_ERROR, /**< Error reading token */
|
TOK_ERROR, /**< Error reading token */
|
||||||
TOK_INVALID,/**< Invalid token */
|
TOK_INVALID,/**< Invalid token */
|
||||||
TOK_STRING,/**< String token */
|
TOK_STRING,/**< String token */
|
||||||
TOK_PIPE,/**< Pipe token */
|
TOK_PIPE,/**< Pipe token */
|
||||||
TOK_END,/**< End token */
|
TOK_END,/**< End token */
|
||||||
TOK_REDIRECT_OUT, /**< redirection token */
|
TOK_REDIRECT_OUT, /**< redirection token */
|
||||||
TOK_REDIRECT_APPEND,/**< redirection append token */
|
TOK_REDIRECT_APPEND,/**< redirection append token */
|
||||||
TOK_REDIRECT_IN,/**< input redirection token */
|
TOK_REDIRECT_IN,/**< input redirection token */
|
||||||
TOK_REDIRECT_FD,/**< redirection to new fd token */
|
TOK_REDIRECT_FD,/**< redirection to new fd token */
|
||||||
TOK_REDIRECT_NOCLOB, /**<? redirection token */
|
TOK_REDIRECT_NOCLOB, /**<? redirection token */
|
||||||
TOK_BACKGROUND,/**< send job to bg token */
|
TOK_BACKGROUND,/**< send job to bg token */
|
||||||
TOK_COMMENT/**< comment token */
|
TOK_COMMENT/**< comment token */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,12 +36,12 @@ enum token_type
|
||||||
*/
|
*/
|
||||||
enum tokenizer_error
|
enum tokenizer_error
|
||||||
{
|
{
|
||||||
TOK_UNTERMINATED_QUOTE,
|
TOK_UNTERMINATED_QUOTE,
|
||||||
TOK_UNTERMINATED_SUBSHELL,
|
TOK_UNTERMINATED_SUBSHELL,
|
||||||
TOK_UNTERMINATED_ESCAPE,
|
TOK_UNTERMINATED_ESCAPE,
|
||||||
TOK_OTHER
|
TOK_OTHER
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,29 +67,29 @@ enum tokenizer_error
|
||||||
*/
|
*/
|
||||||
struct tokenizer
|
struct tokenizer
|
||||||
{
|
{
|
||||||
/** A pointer into the original string, showing where the next token begins */
|
/** A pointer into the original string, showing where the next token begins */
|
||||||
const wchar_t *buff;
|
const wchar_t *buff;
|
||||||
/** A copy of the original string */
|
/** A copy of the original string */
|
||||||
const wchar_t *orig_buff;
|
const wchar_t *orig_buff;
|
||||||
/** A pointer to the last token*/
|
/** A pointer to the last token*/
|
||||||
wchar_t *last;
|
wchar_t *last;
|
||||||
|
|
||||||
/** Type of last token*/
|
/** Type of last token*/
|
||||||
int last_type;
|
int last_type;
|
||||||
/** Length of last token*/
|
/** Length of last token*/
|
||||||
size_t last_len;
|
size_t last_len;
|
||||||
/** Offset of last token*/
|
/** Offset of last token*/
|
||||||
size_t last_pos;
|
size_t last_pos;
|
||||||
/** Whether there are more tokens*/
|
/** Whether there are more tokens*/
|
||||||
bool has_next;
|
bool has_next;
|
||||||
/** Whether incomplete tokens are accepted*/
|
/** Whether incomplete tokens are accepted*/
|
||||||
bool accept_unfinished;
|
bool accept_unfinished;
|
||||||
/** Whether commants should be returned*/
|
/** Whether commants should be returned*/
|
||||||
bool show_comments;
|
bool show_comments;
|
||||||
/** Type of last quote, can be either ' or ".*/
|
/** Type of last quote, can be either ' or ".*/
|
||||||
wchar_t last_quote;
|
wchar_t last_quote;
|
||||||
/** Last error */
|
/** Last error */
|
||||||
int error;
|
int error;
|
||||||
/* Whether we are squashing errors */
|
/* Whether we are squashing errors */
|
||||||
bool squash_errors;
|
bool squash_errors;
|
||||||
|
|
||||||
|
|
122
util.cpp
122
util.cpp
|
@ -1,7 +1,7 @@
|
||||||
/** \file util.c
|
/** \file util.c
|
||||||
Generic utilities library.
|
Generic utilities library.
|
||||||
|
|
||||||
Contains datastructures such as automatically growing array lists, priority queues, etc.
|
Contains datastructures such as automatically growing array lists, priority queues, etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -49,79 +49,79 @@
|
||||||
|
|
||||||
int wcsfilecmp( const wchar_t *a, const wchar_t *b )
|
int wcsfilecmp( const wchar_t *a, const wchar_t *b )
|
||||||
{
|
{
|
||||||
CHECK( a, 0 );
|
CHECK( a, 0 );
|
||||||
CHECK( b, 0 );
|
CHECK( b, 0 );
|
||||||
|
|
||||||
if( *a==0 )
|
if( *a==0 )
|
||||||
{
|
{
|
||||||
if( *b==0)
|
if( *b==0)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if( *b==0 )
|
if( *b==0 )
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
long secondary_diff=0;
|
long secondary_diff=0;
|
||||||
if( iswdigit( *a ) && iswdigit( *b ) )
|
if( iswdigit( *a ) && iswdigit( *b ) )
|
||||||
{
|
{
|
||||||
wchar_t *aend, *bend;
|
wchar_t *aend, *bend;
|
||||||
long al;
|
long al;
|
||||||
long bl;
|
long bl;
|
||||||
long diff;
|
long diff;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
al = wcstol( a, &aend, 10 );
|
al = wcstol( a, &aend, 10 );
|
||||||
bl = wcstol( b, &bend, 10 );
|
bl = wcstol( b, &bend, 10 );
|
||||||
|
|
||||||
if( errno )
|
if( errno )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Huuuuuuuuge numbers - fall back to regular string comparison
|
Huuuuuuuuge numbers - fall back to regular string comparison
|
||||||
*/
|
*/
|
||||||
return wcscmp( a, b );
|
return wcscmp( a, b );
|
||||||
}
|
}
|
||||||
|
|
||||||
diff = al - bl;
|
diff = al - bl;
|
||||||
if( diff )
|
if( diff )
|
||||||
return diff > 0 ? 2 : -2;
|
return diff > 0 ? 2 : -2;
|
||||||
|
|
||||||
secondary_diff = (aend-a) - (bend-b);
|
secondary_diff = (aend-a) - (bend-b);
|
||||||
|
|
||||||
a=aend-1;
|
a=aend-1;
|
||||||
b=bend-1;
|
b=bend-1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int diff = towlower(*a) - towlower(*b);
|
int diff = towlower(*a) - towlower(*b);
|
||||||
if( diff != 0 )
|
if( diff != 0 )
|
||||||
return (diff>0)?2:-2;
|
return (diff>0)?2:-2;
|
||||||
|
|
||||||
secondary_diff = *a-*b;
|
secondary_diff = *a-*b;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = wcsfilecmp( a+1, b+1 );
|
int res = wcsfilecmp( a+1, b+1 );
|
||||||
|
|
||||||
if( abs(res) < 2 )
|
if( abs(res) < 2 )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
No primary difference in rest of string.
|
No primary difference in rest of string.
|
||||||
Use secondary difference on this element if found.
|
Use secondary difference on this element if found.
|
||||||
*/
|
*/
|
||||||
if( secondary_diff )
|
if( secondary_diff )
|
||||||
{
|
{
|
||||||
return secondary_diff > 0 ? 1 :-1;
|
return secondary_diff > 0 ? 1 :-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long get_time()
|
long long get_time()
|
||||||
{
|
{
|
||||||
struct timeval time_struct;
|
struct timeval time_struct;
|
||||||
gettimeofday( &time_struct, 0 );
|
gettimeofday( &time_struct, 0 );
|
||||||
return 1000000ll*time_struct.tv_sec+time_struct.tv_usec;
|
return 1000000ll*time_struct.tv_sec+time_struct.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
util.h
18
util.h
|
@ -1,11 +1,11 @@
|
||||||
/** \file util.h
|
/** \file util.h
|
||||||
Generic utilities library.
|
Generic utilities library.
|
||||||
|
|
||||||
All containers in this library except strinb_buffer_t are written
|
All containers in this library except strinb_buffer_t are written
|
||||||
so that they don't allocate any memory until the first element is
|
so that they don't allocate any memory until the first element is
|
||||||
inserted into them. That way it is known to be very cheap to
|
inserted into them. That way it is known to be very cheap to
|
||||||
initialize various containers at startup, supporting the fish
|
initialize various containers at startup, supporting the fish
|
||||||
notion of doing as much lazy initalization as possible.
|
notion of doing as much lazy initalization as possible.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_UTIL_H
|
#ifndef FISH_UTIL_H
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
*/
|
*/
|
||||||
typedef struct buffer
|
typedef struct buffer
|
||||||
{
|
{
|
||||||
char *buff; /**<data buffer*/
|
char *buff; /**<data buffer*/
|
||||||
size_t length; /**< Size of buffer */
|
size_t length; /**< Size of buffer */
|
||||||
size_t used; /**< Size of data in buffer */
|
size_t used; /**< Size of data in buffer */
|
||||||
}
|
}
|
||||||
buffer_t;
|
buffer_t;
|
||||||
|
|
||||||
|
|
724
wgetopt.cpp
724
wgetopt.cpp
|
@ -1,24 +1,24 @@
|
||||||
/** \file wgetopt.c
|
/** \file wgetopt.c
|
||||||
A version of the getopt library for use with wide character strings.
|
A version of the getopt library for use with wide character strings.
|
||||||
|
|
||||||
This is simply the gnu getopt library, but converted for use with
|
This is simply the gnu getopt library, but converted for use with
|
||||||
wchar_t instead of char. This is not usually useful since the argv
|
wchar_t instead of char. This is not usually useful since the argv
|
||||||
array is always defined to be of type char**, but in fish, all
|
array is always defined to be of type char**, but in fish, all
|
||||||
internal commands use wide characters and hence this library is
|
internal commands use wide characters and hence this library is
|
||||||
useful.
|
useful.
|
||||||
|
|
||||||
If you want to use this version of getopt in your program,
|
If you want to use this version of getopt in your program,
|
||||||
download the fish sourcecode, available at <a
|
download the fish sourcecode, available at <a
|
||||||
href='http://ridiculousfish.com/shell/'>the fish homepage</a>. Extract
|
href='http://ridiculousfish.com/shell/'>the fish homepage</a>. Extract
|
||||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
||||||
directory, include wgetopt.h in your program, and use all the
|
directory, include wgetopt.h in your program, and use all the
|
||||||
regular getopt functions, prefixing every function, global
|
regular getopt functions, prefixing every function, global
|
||||||
variable and structure with a 'w', and use only wide character
|
variable and structure with a 'w', and use only wide character
|
||||||
strings. There are no other functional changes in this version of
|
strings. There are no other functional changes in this version of
|
||||||
getopt besides using wide character strings.
|
getopt besides using wide character strings.
|
||||||
|
|
||||||
For examples of how to use wgetopt, see the fish builtin
|
For examples of how to use wgetopt, see the fish builtin
|
||||||
functions, many of which are defined in builtin.c.
|
functions, many of which are defined in builtin.c.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -70,11 +70,11 @@
|
||||||
|
|
||||||
/* This needs to come after some library #include
|
/* This needs to come after some library #include
|
||||||
to get __GNU_LIBRARY__ defined. */
|
to get __GNU_LIBRARY__ defined. */
|
||||||
#ifdef __GNU_LIBRARY__
|
#ifdef __GNU_LIBRARY__
|
||||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||||
contain conflicting prototypes for getopt. */
|
contain conflicting prototypes for getopt. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#endif /* GNU C library. */
|
#endif /* GNU C library. */
|
||||||
|
|
||||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||||
but it behaves differently for the user, since it allows the user
|
but it behaves differently for the user, since it allows the user
|
||||||
|
@ -170,7 +170,7 @@ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||||
|
|
||||||
static enum
|
static enum
|
||||||
{
|
{
|
||||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
||||||
} ordering;
|
} ordering;
|
||||||
|
|
||||||
/* Value of POSIXLY_CORRECT environment variable. */
|
/* Value of POSIXLY_CORRECT environment variable. */
|
||||||
|
@ -193,13 +193,13 @@ static char *posixly_correct;
|
||||||
#define _(wstr) wstr
|
#define _(wstr) wstr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNU_LIBRARY__
|
#ifdef __GNU_LIBRARY__
|
||||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
/* We want to avoid inclusion of string.h with non-GNU libraries
|
||||||
because there are many ways it can cause trouble.
|
because there are many ways it can cause trouble.
|
||||||
On some systems, it contains special magic macros that don't work
|
On some systems, it contains special magic macros that don't work
|
||||||
in GCC. */
|
in GCC. */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define my_index wcschr
|
#define my_index wcschr
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* Avoid depending on library functions or files
|
/* Avoid depending on library functions or files
|
||||||
|
@ -210,13 +210,13 @@ char *getenv ();
|
||||||
static wchar_t *
|
static wchar_t *
|
||||||
my_index (const wchar_t *str, int chr)
|
my_index (const wchar_t *str, int chr)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
{
|
{
|
||||||
if (*str == chr)
|
if (*str == chr)
|
||||||
return (wchar_t *) str;
|
return (wchar_t *) str;
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If using GCC, we can safely declare strlen this way.
|
/* If using GCC, we can safely declare strlen this way.
|
||||||
|
@ -254,56 +254,56 @@ static int last_nonopt;
|
||||||
static void
|
static void
|
||||||
exchange (wchar_t **argv)
|
exchange (wchar_t **argv)
|
||||||
{
|
{
|
||||||
int bottom = first_nonopt;
|
int bottom = first_nonopt;
|
||||||
int middle = last_nonopt;
|
int middle = last_nonopt;
|
||||||
int top = woptind;
|
int top = woptind;
|
||||||
wchar_t *tem;
|
wchar_t *tem;
|
||||||
|
|
||||||
/* Exchange the shorter segment with the far end of the longer segment.
|
/* Exchange the shorter segment with the far end of the longer segment.
|
||||||
That puts the shorter segment into the right place.
|
That puts the shorter segment into the right place.
|
||||||
It leaves the longer segment in the right place overall,
|
It leaves the longer segment in the right place overall,
|
||||||
but it consists of two parts that need to be swapped next. */
|
but it consists of two parts that need to be swapped next. */
|
||||||
|
|
||||||
while (top > middle && middle > bottom)
|
while (top > middle && middle > bottom)
|
||||||
{
|
{
|
||||||
if (top - middle > middle - bottom)
|
if (top - middle > middle - bottom)
|
||||||
{
|
{
|
||||||
/* Bottom segment is the short one. */
|
/* Bottom segment is the short one. */
|
||||||
int len = middle - bottom;
|
int len = middle - bottom;
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
/* Swap it with the top part of the top segment. */
|
/* Swap it with the top part of the top segment. */
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
tem = argv[bottom + i];
|
tem = argv[bottom + i];
|
||||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||||
argv[top - (middle - bottom) + i] = tem;
|
argv[top - (middle - bottom) + i] = tem;
|
||||||
}
|
}
|
||||||
/* Exclude the moved bottom segment from further swapping. */
|
/* Exclude the moved bottom segment from further swapping. */
|
||||||
top -= len;
|
top -= len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Top segment is the short one. */
|
/* Top segment is the short one. */
|
||||||
int len = top - middle;
|
int len = top - middle;
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
/* Swap it with the bottom part of the bottom segment. */
|
/* Swap it with the bottom part of the bottom segment. */
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
tem = argv[bottom + i];
|
tem = argv[bottom + i];
|
||||||
argv[bottom + i] = argv[middle + i];
|
argv[bottom + i] = argv[middle + i];
|
||||||
argv[middle + i] = tem;
|
argv[middle + i] = tem;
|
||||||
}
|
}
|
||||||
/* Exclude the moved top segment from further swapping. */
|
/* Exclude the moved top segment from further swapping. */
|
||||||
bottom += len;
|
bottom += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update records for the slots the non-options now occupy. */
|
/* Update records for the slots the non-options now occupy. */
|
||||||
|
|
||||||
first_nonopt += (woptind - last_nonopt);
|
first_nonopt += (woptind - last_nonopt);
|
||||||
last_nonopt = woptind;
|
last_nonopt = woptind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the internal data when the first call is made. */
|
/* Initialize the internal data when the first call is made. */
|
||||||
|
@ -311,34 +311,34 @@ exchange (wchar_t **argv)
|
||||||
static const wchar_t *
|
static const wchar_t *
|
||||||
_wgetopt_initialize (const wchar_t *optstring)
|
_wgetopt_initialize (const wchar_t *optstring)
|
||||||
{
|
{
|
||||||
/* Start processing options with ARGV-element 1 (since ARGV-element 0
|
/* Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||||
is the program name); the sequence of previously skipped
|
is the program name); the sequence of previously skipped
|
||||||
non-option ARGV-elements is empty. */
|
non-option ARGV-elements is empty. */
|
||||||
|
|
||||||
first_nonopt = last_nonopt = woptind = 1;
|
first_nonopt = last_nonopt = woptind = 1;
|
||||||
|
|
||||||
nextchar = NULL;
|
nextchar = NULL;
|
||||||
|
|
||||||
posixly_correct = getenv ("POSIXLY_CORRECT");
|
posixly_correct = getenv ("POSIXLY_CORRECT");
|
||||||
|
|
||||||
/* Determine how to handle the ordering of options and nonoptions. */
|
/* Determine how to handle the ordering of options and nonoptions. */
|
||||||
|
|
||||||
if (optstring[0] == '-')
|
if (optstring[0] == '-')
|
||||||
{
|
{
|
||||||
ordering = RETURN_IN_ORDER;
|
ordering = RETURN_IN_ORDER;
|
||||||
++optstring;
|
++optstring;
|
||||||
}
|
}
|
||||||
else if (optstring[0] == '+')
|
else if (optstring[0] == '+')
|
||||||
{
|
{
|
||||||
ordering = REQUIRE_ORDER;
|
ordering = REQUIRE_ORDER;
|
||||||
++optstring;
|
++optstring;
|
||||||
}
|
}
|
||||||
else if (posixly_correct != NULL)
|
else if (posixly_correct != NULL)
|
||||||
ordering = REQUIRE_ORDER;
|
ordering = REQUIRE_ORDER;
|
||||||
else
|
else
|
||||||
ordering = PERMUTE;
|
ordering = PERMUTE;
|
||||||
|
|
||||||
return optstring;
|
return optstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||||
|
@ -400,312 +400,312 @@ _wgetopt_initialize (const wchar_t *optstring)
|
||||||
int
|
int
|
||||||
_wgetopt_internal (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct woption *longopts, int *longind, int long_only)
|
_wgetopt_internal (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct woption *longopts, int *longind, int long_only)
|
||||||
{
|
{
|
||||||
woptarg = NULL;
|
woptarg = NULL;
|
||||||
|
|
||||||
if (woptind == 0)
|
if (woptind == 0)
|
||||||
optstring = _wgetopt_initialize (optstring);
|
optstring = _wgetopt_initialize (optstring);
|
||||||
|
|
||||||
if (nextchar == NULL || *nextchar == '\0')
|
if (nextchar == NULL || *nextchar == '\0')
|
||||||
{
|
{
|
||||||
/* Advance to the next ARGV-element. */
|
/* Advance to the next ARGV-element. */
|
||||||
|
|
||||||
if (ordering == PERMUTE)
|
if (ordering == PERMUTE)
|
||||||
{
|
{
|
||||||
/* If we have just processed some options following some non-options,
|
/* If we have just processed some options following some non-options,
|
||||||
exchange them so that the options come first. */
|
exchange them so that the options come first. */
|
||||||
|
|
||||||
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
||||||
exchange ((wchar_t **) argv);
|
exchange ((wchar_t **) argv);
|
||||||
else if (last_nonopt != woptind)
|
else if (last_nonopt != woptind)
|
||||||
first_nonopt = woptind;
|
first_nonopt = woptind;
|
||||||
|
|
||||||
/* Skip any additional non-options
|
/* Skip any additional non-options
|
||||||
and extend the range of non-options previously skipped. */
|
and extend the range of non-options previously skipped. */
|
||||||
|
|
||||||
while (woptind < argc
|
while (woptind < argc
|
||||||
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||||
woptind++;
|
woptind++;
|
||||||
last_nonopt = woptind;
|
last_nonopt = woptind;
|
||||||
}
|
|
||||||
|
|
||||||
/* The special ARGV-element `--' means premature end of options.
|
|
||||||
Skip it like a null option,
|
|
||||||
then exchange with previous non-options as if it were an option,
|
|
||||||
then skip everything else like a non-option. */
|
|
||||||
|
|
||||||
if (woptind != argc && !wcscmp (argv[woptind], L"--"))
|
|
||||||
{
|
|
||||||
woptind++;
|
|
||||||
|
|
||||||
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
|
||||||
exchange ((wchar_t **) argv);
|
|
||||||
else if (first_nonopt == last_nonopt)
|
|
||||||
first_nonopt = woptind;
|
|
||||||
last_nonopt = argc;
|
|
||||||
|
|
||||||
woptind = argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have done all the ARGV-elements, stop the scan
|
|
||||||
and back over any non-options that we skipped and permuted. */
|
|
||||||
|
|
||||||
if (woptind == argc)
|
|
||||||
{
|
|
||||||
/* Set the next-arg-index to point at the non-options
|
|
||||||
that we previously skipped, so the caller will digest them. */
|
|
||||||
if (first_nonopt != last_nonopt)
|
|
||||||
woptind = first_nonopt;
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have come to a non-option and did not permute it,
|
|
||||||
either stop the scan or describe it to the caller and pass it by. */
|
|
||||||
|
|
||||||
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
|
||||||
{
|
|
||||||
if (ordering == REQUIRE_ORDER)
|
|
||||||
return EOF;
|
|
||||||
woptarg = argv[woptind++];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have found another option-ARGV-element.
|
|
||||||
Skip the initial punctuation. */
|
|
||||||
|
|
||||||
nextchar = (argv[woptind] + 1
|
|
||||||
+ (longopts != NULL && argv[woptind][1] == '-'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode the current option-ARGV-element. */
|
/* The special ARGV-element `--' means premature end of options.
|
||||||
|
Skip it like a null option,
|
||||||
|
then exchange with previous non-options as if it were an option,
|
||||||
|
then skip everything else like a non-option. */
|
||||||
|
|
||||||
/* Check whether the ARGV-element is a long option.
|
if (woptind != argc && !wcscmp (argv[woptind], L"--"))
|
||||||
|
|
||||||
If long_only and the ARGV-element has the form "-f", where f is
|
|
||||||
a valid short option, don't consider it an abbreviated form of
|
|
||||||
a long option that starts with f. Otherwise there would be no
|
|
||||||
way to give the -f short option.
|
|
||||||
|
|
||||||
On the other hand, if there's a long option "fubar" and
|
|
||||||
the ARGV-element is "-fu", do consider that an abbreviation of
|
|
||||||
the long option, just like "--fu", and not "-f" with arg "u".
|
|
||||||
|
|
||||||
This distinction seems to be the most useful approach. */
|
|
||||||
|
|
||||||
if (longopts != NULL
|
|
||||||
&& (argv[woptind][1] == '-'
|
|
||||||
|| (long_only && (argv[woptind][2] || !my_index (optstring, argv[woptind][1])))))
|
|
||||||
{
|
{
|
||||||
wchar_t *nameend;
|
woptind++;
|
||||||
const struct woption *p;
|
|
||||||
const struct woption *pfound = NULL;
|
|
||||||
int exact = 0;
|
|
||||||
int ambig = 0;
|
|
||||||
int indfound = 0; /* set to zero by Anton */
|
|
||||||
int option_index;
|
|
||||||
|
|
||||||
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
|
if (first_nonopt != last_nonopt && last_nonopt != woptind)
|
||||||
/* Do nothing. */ ;
|
exchange ((wchar_t **) argv);
|
||||||
|
else if (first_nonopt == last_nonopt)
|
||||||
|
first_nonopt = woptind;
|
||||||
|
last_nonopt = argc;
|
||||||
|
|
||||||
/* Test all long options for either exact match
|
woptind = argc;
|
||||||
or abbreviated matches. */
|
|
||||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
|
||||||
if (!wcsncmp(p->name, nextchar, nameend - nextchar))
|
|
||||||
{
|
|
||||||
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen (p->name))
|
|
||||||
{
|
|
||||||
/* Exact match found. */
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
exact = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (pfound == NULL)
|
|
||||||
{
|
|
||||||
/* First nonexact match found. */
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* Second or later nonexact match found. */
|
|
||||||
ambig = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ambig && !exact)
|
|
||||||
{
|
|
||||||
if (wopterr)
|
|
||||||
fwprintf (stderr, _(L"%ls: Option '%ls' is ambiguous\n"),
|
|
||||||
argv[0], argv[woptind]);
|
|
||||||
nextchar += wcslen (nextchar);
|
|
||||||
woptind++;
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pfound != NULL)
|
|
||||||
{
|
|
||||||
option_index = indfound;
|
|
||||||
woptind++;
|
|
||||||
if (*nameend)
|
|
||||||
{
|
|
||||||
/* Don't test has_arg with >, because some C compilers don't
|
|
||||||
allow it to be used on enums. */
|
|
||||||
if (pfound->has_arg)
|
|
||||||
woptarg = nameend + 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (wopterr)
|
|
||||||
{
|
|
||||||
if (argv[woptind - 1][1] == '-')
|
|
||||||
/* --option */
|
|
||||||
fwprintf (stderr,
|
|
||||||
_(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
|
||||||
argv[0], pfound->name);
|
|
||||||
else
|
|
||||||
/* +option or -option */
|
|
||||||
fwprintf (stderr,
|
|
||||||
_(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
|
||||||
argv[0], argv[woptind - 1][0], pfound->name);
|
|
||||||
}
|
|
||||||
nextchar += wcslen (nextchar);
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pfound->has_arg == 1)
|
|
||||||
{
|
|
||||||
if (woptind < argc)
|
|
||||||
woptarg = argv[woptind++];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (wopterr)
|
|
||||||
fwprintf (stderr, _(L"%ls: Option '%ls' requires an argument\n"),
|
|
||||||
argv[0], argv[woptind - 1]);
|
|
||||||
nextchar += wcslen (nextchar);
|
|
||||||
return optstring[0] == ':' ? ':' : '?';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nextchar += wcslen (nextchar);
|
|
||||||
if (longind != NULL)
|
|
||||||
*longind = option_index;
|
|
||||||
if (pfound->flag)
|
|
||||||
{
|
|
||||||
*(pfound->flag) = pfound->val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return pfound->val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
|
||||||
or the option starts with '--' or is not a valid short
|
|
||||||
option, then it's an error.
|
|
||||||
Otherwise interpret it as a short option. */
|
|
||||||
if (!long_only || argv[woptind][1] == '-'
|
|
||||||
|| my_index (optstring, *nextchar) == NULL)
|
|
||||||
{
|
|
||||||
if (wopterr)
|
|
||||||
{
|
|
||||||
if (argv[woptind][1] == '-')
|
|
||||||
/* --option */
|
|
||||||
fwprintf (stderr, _(L"%ls: Unrecognized option '--%ls'\n"),
|
|
||||||
argv[0], nextchar);
|
|
||||||
else
|
|
||||||
/* +option or -option */
|
|
||||||
fwprintf (stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"),
|
|
||||||
argv[0], argv[woptind][0], nextchar);
|
|
||||||
}
|
|
||||||
nextchar = (wchar_t *) L"";
|
|
||||||
woptind++;
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at and handle the next short option-character. */
|
/* If we have done all the ARGV-elements, stop the scan
|
||||||
|
and back over any non-options that we skipped and permuted. */
|
||||||
|
|
||||||
{
|
if (woptind == argc)
|
||||||
wchar_t c = *nextchar++;
|
{
|
||||||
wchar_t *temp = const_cast<wchar_t*>(my_index (optstring, c));
|
/* Set the next-arg-index to point at the non-options
|
||||||
|
that we previously skipped, so the caller will digest them. */
|
||||||
|
if (first_nonopt != last_nonopt)
|
||||||
|
woptind = first_nonopt;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
/* Increment `woptind' when we start to process its last character. */
|
/* If we have come to a non-option and did not permute it,
|
||||||
if (*nextchar == '\0')
|
either stop the scan or describe it to the caller and pass it by. */
|
||||||
++woptind;
|
|
||||||
|
|
||||||
if (temp == NULL || c == ':')
|
if ((argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
|
||||||
{
|
{
|
||||||
if (wopterr)
|
if (ordering == REQUIRE_ORDER)
|
||||||
{
|
return EOF;
|
||||||
if (posixly_correct)
|
woptarg = argv[woptind++];
|
||||||
/* 1003.2 specifies the format of this message. */
|
return 1;
|
||||||
fwprintf (stderr, _(L"%ls: Illegal option -- %lc\n"), argv[0], c);
|
}
|
||||||
else
|
|
||||||
fwprintf (stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], c);
|
/* We have found another option-ARGV-element.
|
||||||
}
|
Skip the initial punctuation. */
|
||||||
woptopt = c;
|
|
||||||
return '?';
|
nextchar = (argv[woptind] + 1
|
||||||
}
|
+ (longopts != NULL && argv[woptind][1] == '-'));
|
||||||
if (temp[1] == ':')
|
}
|
||||||
{
|
|
||||||
if (temp[2] == ':')
|
/* Decode the current option-ARGV-element. */
|
||||||
{
|
|
||||||
/* This is an option that accepts an argument optionally. */
|
/* Check whether the ARGV-element is a long option.
|
||||||
if (*nextchar != '\0')
|
|
||||||
{
|
If long_only and the ARGV-element has the form "-f", where f is
|
||||||
woptarg = nextchar;
|
a valid short option, don't consider it an abbreviated form of
|
||||||
woptind++;
|
a long option that starts with f. Otherwise there would be no
|
||||||
}
|
way to give the -f short option.
|
||||||
else
|
|
||||||
woptarg = NULL;
|
On the other hand, if there's a long option "fubar" and
|
||||||
nextchar = NULL;
|
the ARGV-element is "-fu", do consider that an abbreviation of
|
||||||
}
|
the long option, just like "--fu", and not "-f" with arg "u".
|
||||||
else
|
|
||||||
{
|
This distinction seems to be the most useful approach. */
|
||||||
/* This is an option that requires an argument. */
|
|
||||||
if (*nextchar != '\0')
|
if (longopts != NULL
|
||||||
{
|
&& (argv[woptind][1] == '-'
|
||||||
woptarg = nextchar;
|
|| (long_only && (argv[woptind][2] || !my_index (optstring, argv[woptind][1])))))
|
||||||
/* If we end this ARGV-element by taking the rest as an arg,
|
{
|
||||||
we must advance to the next element now. */
|
wchar_t *nameend;
|
||||||
woptind++;
|
const struct woption *p;
|
||||||
}
|
const struct woption *pfound = NULL;
|
||||||
else if (woptind == argc)
|
int exact = 0;
|
||||||
{
|
int ambig = 0;
|
||||||
if (wopterr)
|
int indfound = 0; /* set to zero by Anton */
|
||||||
{
|
int option_index;
|
||||||
/* 1003.2 specifies the format of this message. */
|
|
||||||
fwprintf (stderr, _(L"%ls: Option requires an argument -- %lc\n"),
|
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
|
||||||
argv[0], c);
|
/* Do nothing. */ ;
|
||||||
}
|
|
||||||
woptopt = c;
|
/* Test all long options for either exact match
|
||||||
if (optstring[0] == ':')
|
or abbreviated matches. */
|
||||||
c = ':';
|
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||||
else
|
if (!wcsncmp(p->name, nextchar, nameend - nextchar))
|
||||||
c = '?';
|
{
|
||||||
}
|
if ((unsigned int)(nameend - nextchar) == (unsigned int)wcslen (p->name))
|
||||||
else
|
{
|
||||||
/* We already incremented `woptind' once;
|
/* Exact match found. */
|
||||||
increment it again when taking next ARGV-elt as argument. */
|
pfound = p;
|
||||||
woptarg = argv[woptind++];
|
indfound = option_index;
|
||||||
nextchar = NULL;
|
exact = 1;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
return c;
|
else if (pfound == NULL)
|
||||||
}
|
{
|
||||||
|
/* First nonexact match found. */
|
||||||
|
pfound = p;
|
||||||
|
indfound = option_index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Second or later nonexact match found. */
|
||||||
|
ambig = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ambig && !exact)
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
fwprintf (stderr, _(L"%ls: Option '%ls' is ambiguous\n"),
|
||||||
|
argv[0], argv[woptind]);
|
||||||
|
nextchar += wcslen (nextchar);
|
||||||
|
woptind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfound != NULL)
|
||||||
|
{
|
||||||
|
option_index = indfound;
|
||||||
|
woptind++;
|
||||||
|
if (*nameend)
|
||||||
|
{
|
||||||
|
/* Don't test has_arg with >, because some C compilers don't
|
||||||
|
allow it to be used on enums. */
|
||||||
|
if (pfound->has_arg)
|
||||||
|
woptarg = nameend + 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
{
|
||||||
|
if (argv[woptind - 1][1] == '-')
|
||||||
|
/* --option */
|
||||||
|
fwprintf (stderr,
|
||||||
|
_(L"%ls: Option '--%ls' doesn't allow an argument\n"),
|
||||||
|
argv[0], pfound->name);
|
||||||
|
else
|
||||||
|
/* +option or -option */
|
||||||
|
fwprintf (stderr,
|
||||||
|
_(L"%ls: Option '%lc%ls' doesn't allow an argument\n"),
|
||||||
|
argv[0], argv[woptind - 1][0], pfound->name);
|
||||||
|
}
|
||||||
|
nextchar += wcslen (nextchar);
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pfound->has_arg == 1)
|
||||||
|
{
|
||||||
|
if (woptind < argc)
|
||||||
|
woptarg = argv[woptind++];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
fwprintf (stderr, _(L"%ls: Option '%ls' requires an argument\n"),
|
||||||
|
argv[0], argv[woptind - 1]);
|
||||||
|
nextchar += wcslen (nextchar);
|
||||||
|
return optstring[0] == ':' ? ':' : '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextchar += wcslen (nextchar);
|
||||||
|
if (longind != NULL)
|
||||||
|
*longind = option_index;
|
||||||
|
if (pfound->flag)
|
||||||
|
{
|
||||||
|
*(pfound->flag) = pfound->val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pfound->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||||
|
or the option starts with '--' or is not a valid short
|
||||||
|
option, then it's an error.
|
||||||
|
Otherwise interpret it as a short option. */
|
||||||
|
if (!long_only || argv[woptind][1] == '-'
|
||||||
|
|| my_index (optstring, *nextchar) == NULL)
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
{
|
||||||
|
if (argv[woptind][1] == '-')
|
||||||
|
/* --option */
|
||||||
|
fwprintf (stderr, _(L"%ls: Unrecognized option '--%ls'\n"),
|
||||||
|
argv[0], nextchar);
|
||||||
|
else
|
||||||
|
/* +option or -option */
|
||||||
|
fwprintf (stderr, _(L"%ls: Unrecognized option '%lc%ls'\n"),
|
||||||
|
argv[0], argv[woptind][0], nextchar);
|
||||||
|
}
|
||||||
|
nextchar = (wchar_t *) L"";
|
||||||
|
woptind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look at and handle the next short option-character. */
|
||||||
|
|
||||||
|
{
|
||||||
|
wchar_t c = *nextchar++;
|
||||||
|
wchar_t *temp = const_cast<wchar_t*>(my_index (optstring, c));
|
||||||
|
|
||||||
|
/* Increment `woptind' when we start to process its last character. */
|
||||||
|
if (*nextchar == '\0')
|
||||||
|
++woptind;
|
||||||
|
|
||||||
|
if (temp == NULL || c == ':')
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
{
|
||||||
|
if (posixly_correct)
|
||||||
|
/* 1003.2 specifies the format of this message. */
|
||||||
|
fwprintf (stderr, _(L"%ls: Illegal option -- %lc\n"), argv[0], c);
|
||||||
|
else
|
||||||
|
fwprintf (stderr, _(L"%ls: Invalid option -- %lc\n"), argv[0], c);
|
||||||
|
}
|
||||||
|
woptopt = c;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
if (temp[1] == ':')
|
||||||
|
{
|
||||||
|
if (temp[2] == ':')
|
||||||
|
{
|
||||||
|
/* This is an option that accepts an argument optionally. */
|
||||||
|
if (*nextchar != '\0')
|
||||||
|
{
|
||||||
|
woptarg = nextchar;
|
||||||
|
woptind++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
woptarg = NULL;
|
||||||
|
nextchar = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is an option that requires an argument. */
|
||||||
|
if (*nextchar != '\0')
|
||||||
|
{
|
||||||
|
woptarg = nextchar;
|
||||||
|
/* If we end this ARGV-element by taking the rest as an arg,
|
||||||
|
we must advance to the next element now. */
|
||||||
|
woptind++;
|
||||||
|
}
|
||||||
|
else if (woptind == argc)
|
||||||
|
{
|
||||||
|
if (wopterr)
|
||||||
|
{
|
||||||
|
/* 1003.2 specifies the format of this message. */
|
||||||
|
fwprintf (stderr, _(L"%ls: Option requires an argument -- %lc\n"),
|
||||||
|
argv[0], c);
|
||||||
|
}
|
||||||
|
woptopt = c;
|
||||||
|
if (optstring[0] == ':')
|
||||||
|
c = ':';
|
||||||
|
else
|
||||||
|
c = '?';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* We already incremented `woptind' once;
|
||||||
|
increment it again when taking next ARGV-elt as argument. */
|
||||||
|
woptarg = argv[woptind++];
|
||||||
|
nextchar = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring)
|
wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring)
|
||||||
{
|
{
|
||||||
return _wgetopt_internal (argc, argv, optstring,
|
return _wgetopt_internal (argc, argv, optstring,
|
||||||
(const struct woption *) 0,
|
(const struct woption *) 0,
|
||||||
(int *) 0,
|
(int *) 0,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
wgetopt_long (int argc, wchar_t *const *argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
wgetopt_long (int argc, wchar_t *const *argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
||||||
{
|
{
|
||||||
return _wgetopt_internal (argc, argv, options, long_options, opt_index, 0);
|
return _wgetopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
wgetopt_long_only (int argc, wchar_t *const *argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
wgetopt_long_only (int argc, wchar_t *const *argv, const wchar_t *options, const struct woption *long_options, int *opt_index)
|
||||||
{
|
{
|
||||||
return _wgetopt_internal (argc, argv, options, long_options, opt_index, 1);
|
return _wgetopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||||
}
|
}
|
||||||
|
|
110
wgetopt.h
110
wgetopt.h
|
@ -1,24 +1,24 @@
|
||||||
/** \file wgetopt.h
|
/** \file wgetopt.h
|
||||||
A version of the getopt library for use with wide character strings.
|
A version of the getopt library for use with wide character strings.
|
||||||
|
|
||||||
This is simply the gnu getopt library, but converted for use with
|
This is simply the gnu getopt library, but converted for use with
|
||||||
wchar_t instead of char. This is not usually useful since the argv
|
wchar_t instead of char. This is not usually useful since the argv
|
||||||
array is always defined to be of type char**, but in fish, all
|
array is always defined to be of type char**, but in fish, all
|
||||||
internal commands use wide characters and hence this library is
|
internal commands use wide characters and hence this library is
|
||||||
useful.
|
useful.
|
||||||
|
|
||||||
If you want to use this version of getopt in your program,
|
If you want to use this version of getopt in your program,
|
||||||
download the fish sourcecode, available at <a
|
download the fish sourcecode, available at <a
|
||||||
href='http://ridiculousfish.com/shell/'>the fish homepage</a>. Extract
|
href='http://ridiculousfish.com/shell/'>the fish homepage</a>. Extract
|
||||||
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
the sourcode, copy wgetopt.c and wgetopt.h into your program
|
||||||
directory, include wgetopt.h in your program, and use all the
|
directory, include wgetopt.h in your program, and use all the
|
||||||
regular getopt functions, prefixing every function, global
|
regular getopt functions, prefixing every function, global
|
||||||
variable and structure with a 'w', and use only wide character
|
variable and structure with a 'w', and use only wide character
|
||||||
strings. There are no other functional changes in this version of
|
strings. There are no other functional changes in this version of
|
||||||
getopt besides using wide character strings.
|
getopt besides using wide character strings.
|
||||||
|
|
||||||
For examples of how to use wgetopt, see the fish builtin
|
For examples of how to use wgetopt, see the fish builtin
|
||||||
functions, many of which are defined in builtin.c.
|
functions, many of which are defined in builtin.c.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ Cambridge, MA 02139, USA. */
|
||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -90,9 +90,9 @@ extern int woptopt;
|
||||||
zero.
|
zero.
|
||||||
|
|
||||||
The field `has_arg' is:
|
The field `has_arg' is:
|
||||||
no_argument (or 0) if the option does not take an argument,
|
no_argument (or 0) if the option does not take an argument,
|
||||||
required_argument (or 1) if the option requires an argument,
|
required_argument (or 1) if the option requires an argument,
|
||||||
optional_argument (or 2) if the option takes an optional argument.
|
optional_argument (or 2) if the option takes an optional argument.
|
||||||
|
|
||||||
If the field `flag' is not NULL, it points to a variable that is set
|
If the field `flag' is not NULL, it points to a variable that is set
|
||||||
to the value given in the field `val' when the option is found, but
|
to the value given in the field `val' when the option is found, but
|
||||||
|
@ -107,32 +107,32 @@ extern int woptopt;
|
||||||
|
|
||||||
struct woption
|
struct woption
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
long name for switch
|
long name for switch
|
||||||
*/
|
*/
|
||||||
#if defined (__STDC__) && __STDC__
|
#if defined (__STDC__) && __STDC__
|
||||||
const wchar_t *name;
|
const wchar_t *name;
|
||||||
#else
|
#else
|
||||||
wchar_t *name;
|
wchar_t *name;
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
Must be one of no_argument, required_argument and
|
Must be one of no_argument, required_argument and
|
||||||
optional_argument.
|
optional_argument.
|
||||||
|
|
||||||
has_arg can't be an enum because some compilers complain about
|
has_arg can't be an enum because some compilers complain about
|
||||||
type mismatches in all the code that assumes it is an int.
|
type mismatches in all the code that assumes it is an int.
|
||||||
*/
|
*/
|
||||||
int has_arg;
|
int has_arg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If non-null, the flag whose value should be set if this switch is encountered
|
If non-null, the flag whose value should be set if this switch is encountered
|
||||||
*/
|
*/
|
||||||
int *flag;
|
int *flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If \c flag is non-null, this is the value that flag will be set
|
If \c flag is non-null, this is the value that flag will be set
|
||||||
to. Otherwise, this is the return-value of the function call.
|
to. Otherwise, this is the return-value of the function call.
|
||||||
*/
|
*/
|
||||||
int val;
|
int val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,20 +141,20 @@ struct woption
|
||||||
/**
|
/**
|
||||||
Specifies that a switch does not accept an argument
|
Specifies that a switch does not accept an argument
|
||||||
*/
|
*/
|
||||||
#define no_argument 0
|
#define no_argument 0
|
||||||
/**
|
/**
|
||||||
Specifies that a switch requires an argument
|
Specifies that a switch requires an argument
|
||||||
*/
|
*/
|
||||||
#define required_argument 1
|
#define required_argument 1
|
||||||
/**
|
/**
|
||||||
Specifies that a switch accepts an optional argument
|
Specifies that a switch accepts an optional argument
|
||||||
*/
|
*/
|
||||||
#define optional_argument 2
|
#define optional_argument 2
|
||||||
|
|
||||||
#if defined (__STDC__) && __STDC__
|
#if defined (__STDC__) && __STDC__
|
||||||
#ifdef __GNU_LIBRARY__
|
#ifdef __GNU_LIBRARY__
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt (int argc, wchar_t *const *argv, const wchar_t *shortopts);
|
extern int wgetopt (int argc, wchar_t *const *argv, const wchar_t *shortopts);
|
||||||
#else /* not __GNU_LIBRARY__ */
|
#else /* not __GNU_LIBRARY__ */
|
||||||
|
@ -162,48 +162,48 @@ extern int wgetopt (int argc, wchar_t *const *argv, const wchar_t *shortopts);
|
||||||
extern int wgetopt ();
|
extern int wgetopt ();
|
||||||
#endif /* __GNU_LIBRARY__ */
|
#endif /* __GNU_LIBRARY__ */
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt_long (int argc, wchar_t *const *argv, const wchar_t *shortopts,
|
extern int wgetopt_long (int argc, wchar_t *const *argv, const wchar_t *shortopts,
|
||||||
const struct woption *longopts, int *longind);
|
const struct woption *longopts, int *longind);
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt_long_only (int argc, wchar_t *const *argv,
|
extern int wgetopt_long_only (int argc, wchar_t *const *argv,
|
||||||
const wchar_t *shortopts,
|
const wchar_t *shortopts,
|
||||||
const struct woption *longopts, int *longind);
|
const struct woption *longopts, int *longind);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Internal only. Users should not call this directly.
|
Internal only. Users should not call this directly.
|
||||||
*/
|
*/
|
||||||
extern int _wgetopt_internal (int argc, wchar_t *const *argv,
|
extern int _wgetopt_internal (int argc, wchar_t *const *argv,
|
||||||
const wchar_t *shortopts,
|
const wchar_t *shortopts,
|
||||||
const struct woption *longopts, int *longind,
|
const struct woption *longopts, int *longind,
|
||||||
int long_only);
|
int long_only);
|
||||||
#else /* not __STDC__ */
|
#else /* not __STDC__ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt ();
|
extern int wgetopt ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt_long ();
|
extern int wgetopt_long ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get options from argument list. See the glibc manual for information on how to use this function.
|
Get options from argument list. See the glibc manual for information on how to use this function.
|
||||||
*/
|
*/
|
||||||
extern int wgetopt_long_only ();
|
extern int wgetopt_long_only ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Internal only. Users should not call this directly.
|
Internal only. Users should not call this directly.
|
||||||
*/
|
*/
|
||||||
extern int _wgetopt_internal ();
|
extern int _wgetopt_internal ();
|
||||||
#endif /* __STDC__ */
|
#endif /* __STDC__ */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
1364
wildcard.cpp
1364
wildcard.cpp
File diff suppressed because it is too large
Load diff
56
wildcard.h
56
wildcard.h
|
@ -31,40 +31,40 @@ class completion_t;
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/** Character representing any character except '/' */
|
/** Character representing any character except '/' */
|
||||||
ANY_CHAR = WILDCARD_RESERVED,
|
ANY_CHAR = WILDCARD_RESERVED,
|
||||||
|
|
||||||
/** Character representing any character string not containing '/' (A slash) */
|
/** Character representing any character string not containing '/' (A slash) */
|
||||||
ANY_STRING,
|
ANY_STRING,
|
||||||
|
|
||||||
/** Character representing any character string */
|
/** Character representing any character string */
|
||||||
ANY_STRING_RECURSIVE,
|
ANY_STRING_RECURSIVE,
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Expand the wildcard by matching against the filesystem.
|
Expand the wildcard by matching against the filesystem.
|
||||||
|
|
||||||
New strings are allocated using malloc and should be freed by the caller.
|
New strings are allocated using malloc and should be freed by the caller.
|
||||||
|
|
||||||
wildcard_expand works by dividing the wildcard into segments at
|
wildcard_expand works by dividing the wildcard into segments at
|
||||||
each directory boundary. Each segment is processed separatly. All
|
each directory boundary. Each segment is processed separatly. All
|
||||||
except the last segment are handled by matching the wildcard
|
except the last segment are handled by matching the wildcard
|
||||||
segment against all subdirectories of matching directories, and
|
segment against all subdirectories of matching directories, and
|
||||||
recursively calling wildcard_expand for matches. On the last
|
recursively calling wildcard_expand for matches. On the last
|
||||||
segment, matching is made to any file, and all matches are
|
segment, matching is made to any file, and all matches are
|
||||||
inserted to the list.
|
inserted to the list.
|
||||||
|
|
||||||
If wildcard_expand encounters any errors (such as insufficient
|
If wildcard_expand encounters any errors (such as insufficient
|
||||||
priviliges) during matching, no error messages will be printed and
|
priviliges) during matching, no error messages will be printed and
|
||||||
wildcard_expand will continue the matching process.
|
wildcard_expand will continue the matching process.
|
||||||
|
|
||||||
\param wc The wildcard string
|
\param wc The wildcard string
|
||||||
\param base_dir The base directory of the filesystem to perform the match against
|
\param base_dir The base directory of the filesystem to perform the match against
|
||||||
\param flags flags for the search. Can be any combination of ACCEPT_INCOMPLETE and EXECUTABLES_ONLY
|
\param flags flags for the search. Can be any combination of ACCEPT_INCOMPLETE and EXECUTABLES_ONLY
|
||||||
\param out The list in which to put the output
|
\param out The list in which to put the output
|
||||||
|
|
||||||
\return 1 if matches where found, 0 otherwise. Return -1 on abort (I.e. ^C was pressed).
|
\return 1 if matches where found, 0 otherwise. Return -1 on abort (I.e. ^C was pressed).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> &out );
|
int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> &out );
|
||||||
|
@ -87,10 +87,10 @@ int wildcard_has( const wchar_t *str, int internal );
|
||||||
Test wildcard completion
|
Test wildcard completion
|
||||||
*/
|
*/
|
||||||
bool wildcard_complete(const wcstring &str,
|
bool wildcard_complete(const wcstring &str,
|
||||||
const wchar_t *wc,
|
const wchar_t *wc,
|
||||||
const wchar_t *desc,
|
const wchar_t *desc,
|
||||||
wcstring (*desc_func)(const wcstring &),
|
wcstring (*desc_func)(const wcstring &),
|
||||||
std::vector<completion_t> &out,
|
std::vector<completion_t> &out,
|
||||||
expand_flags_t flags );
|
expand_flags_t flags );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
160
wutil.cpp
160
wutil.cpp
|
@ -1,6 +1,6 @@
|
||||||
/** \file wutil.c
|
/** \file wutil.c
|
||||||
Wide character equivalents of various standard unix
|
Wide character equivalents of various standard unix
|
||||||
functions.
|
functions.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -108,34 +108,34 @@ bool wreaddir(DIR *dir, std::wstring &out_name)
|
||||||
|
|
||||||
wchar_t *wgetcwd( wchar_t *buff, size_t sz )
|
wchar_t *wgetcwd( wchar_t *buff, size_t sz )
|
||||||
{
|
{
|
||||||
char *buffc = (char *)malloc( sz*MAX_UTF8_BYTES);
|
char *buffc = (char *)malloc( sz*MAX_UTF8_BYTES);
|
||||||
char *res;
|
char *res;
|
||||||
wchar_t *ret = 0;
|
wchar_t *ret = 0;
|
||||||
|
|
||||||
if( !buffc )
|
if( !buffc )
|
||||||
{
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = getcwd( buffc, sz*MAX_UTF8_BYTES );
|
res = getcwd( buffc, sz*MAX_UTF8_BYTES );
|
||||||
if( res )
|
if( res )
|
||||||
{
|
{
|
||||||
if( (size_t)-1 != mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) )
|
if( (size_t)-1 != mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) )
|
||||||
{
|
{
|
||||||
ret = buff;
|
ret = buff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free( buffc );
|
free( buffc );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wchdir( const wcstring &dir )
|
int wchdir( const wcstring &dir )
|
||||||
{
|
{
|
||||||
cstring tmp = wcs2string(dir);
|
cstring tmp = wcs2string(dir);
|
||||||
return chdir( tmp.c_str() );
|
return chdir( tmp.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *wfopen(const wcstring &path, const char *mode)
|
FILE *wfopen(const wcstring &path, const char *mode)
|
||||||
|
@ -266,40 +266,40 @@ int wunlink(const wcstring &file_name)
|
||||||
|
|
||||||
void wperror(const wcstring &s)
|
void wperror(const wcstring &s)
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
if( !s.empty() )
|
if( !s.empty() )
|
||||||
{
|
{
|
||||||
fwprintf( stderr, L"%ls: ", s.c_str() );
|
fwprintf( stderr, L"%ls: ", s.c_str() );
|
||||||
}
|
}
|
||||||
fwprintf( stderr, L"%s\n", strerror( e ) );
|
fwprintf( stderr, L"%s\n", strerror( e ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_REALPATH_NULL
|
#ifdef HAVE_REALPATH_NULL
|
||||||
|
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
||||||
{
|
{
|
||||||
cstring tmp = wcs2string(pathname);
|
cstring tmp = wcs2string(pathname);
|
||||||
char *narrow_res = realpath( tmp.c_str(), 0 );
|
char *narrow_res = realpath( tmp.c_str(), 0 );
|
||||||
wchar_t *res;
|
wchar_t *res;
|
||||||
|
|
||||||
if( !narrow_res )
|
if( !narrow_res )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( resolved_path )
|
if( resolved_path )
|
||||||
{
|
{
|
||||||
wchar_t *tmp2 = str2wcs( narrow_res );
|
wchar_t *tmp2 = str2wcs( narrow_res );
|
||||||
wcslcpy( resolved_path, tmp2, PATH_MAX );
|
wcslcpy( resolved_path, tmp2, PATH_MAX );
|
||||||
free( tmp2 );
|
free( tmp2 );
|
||||||
res = resolved_path;
|
res = resolved_path;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = str2wcs( narrow_res );
|
res = str2wcs( narrow_res );
|
||||||
}
|
}
|
||||||
|
|
||||||
free( narrow_res );
|
free( narrow_res );
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -307,25 +307,25 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
|
||||||
{
|
{
|
||||||
cstring tmp = wcs2string(pathname);
|
cstring tmp = wcs2string(pathname);
|
||||||
char narrow_buff[PATH_MAX];
|
char narrow_buff[PATH_MAX];
|
||||||
char *narrow_res = realpath( tmp.c_str(), narrow_buff );
|
char *narrow_res = realpath( tmp.c_str(), narrow_buff );
|
||||||
wchar_t *res;
|
wchar_t *res;
|
||||||
|
|
||||||
if( !narrow_res )
|
if( !narrow_res )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( resolved_path )
|
if( resolved_path )
|
||||||
{
|
{
|
||||||
wchar_t *tmp2 = str2wcs( narrow_res );
|
wchar_t *tmp2 = str2wcs( narrow_res );
|
||||||
wcslcpy( resolved_path, tmp2, PATH_MAX );
|
wcslcpy( resolved_path, tmp2, PATH_MAX );
|
||||||
free( tmp2 );
|
free( tmp2 );
|
||||||
res = resolved_path;
|
res = resolved_path;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = str2wcs( narrow_res );
|
res = str2wcs( narrow_res );
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -352,8 +352,8 @@ wcstring wbasename( const wcstring &path )
|
||||||
/* Really init wgettext */
|
/* Really init wgettext */
|
||||||
static void wgettext_really_init() {
|
static void wgettext_really_init() {
|
||||||
pthread_mutex_init(&wgettext_lock, NULL);
|
pthread_mutex_init(&wgettext_lock, NULL);
|
||||||
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
|
||||||
textdomain( PACKAGE_NAME );
|
textdomain( PACKAGE_NAME );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -367,15 +367,15 @@ static void wgettext_init_if_necessary()
|
||||||
|
|
||||||
const wchar_t *wgettext( const wchar_t *in )
|
const wchar_t *wgettext( const wchar_t *in )
|
||||||
{
|
{
|
||||||
if( !in )
|
if( !in )
|
||||||
return in;
|
return in;
|
||||||
|
|
||||||
// preserve errno across this since this is often used in printing error messages
|
// preserve errno across this since this is often used in printing error messages
|
||||||
int err = errno;
|
int err = errno;
|
||||||
|
|
||||||
wgettext_init_if_necessary();
|
wgettext_init_if_necessary();
|
||||||
|
|
||||||
wcstring key = in;
|
wcstring key = in;
|
||||||
scoped_lock lock(wgettext_lock);
|
scoped_lock lock(wgettext_lock);
|
||||||
|
|
||||||
wcstring *& val = wgettext_map[key];
|
wcstring *& val = wgettext_map[key];
|
||||||
|
@ -384,14 +384,14 @@ const wchar_t *wgettext( const wchar_t *in )
|
||||||
char *out = gettext(mbs_in.c_str());
|
char *out = gettext(mbs_in.c_str());
|
||||||
val = new wcstring(format_string(L"%s", out));
|
val = new wcstring(format_string(L"%s", out));
|
||||||
}
|
}
|
||||||
errno = err;
|
errno = err;
|
||||||
return val->c_str();
|
return val->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstring wgettext2(const wcstring &in) {
|
wcstring wgettext2(const wcstring &in) {
|
||||||
wgettext_init_if_necessary();
|
wgettext_init_if_necessary();
|
||||||
std::string mbs_in = wcs2string(in);
|
std::string mbs_in = wcs2string(in);
|
||||||
char *out = gettext( mbs_in.c_str() );
|
char *out = gettext( mbs_in.c_str() );
|
||||||
wcstring result = format_string(L"%s", out);
|
wcstring result = format_string(L"%s", out);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -400,28 +400,28 @@ const wchar_t *wgetenv( const wcstring &name )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
cstring name_narrow = wcs2string(name);
|
cstring name_narrow = wcs2string(name);
|
||||||
char *res_narrow = getenv( name_narrow.c_str() );
|
char *res_narrow = getenv( name_narrow.c_str() );
|
||||||
static wcstring out;
|
static wcstring out;
|
||||||
|
|
||||||
if( !res_narrow )
|
if( !res_narrow )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out = format_string(L"%s", res_narrow);
|
out = format_string(L"%s", res_narrow);
|
||||||
return out.c_str();
|
return out.c_str();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmkdir( const wcstring &name, int mode )
|
int wmkdir( const wcstring &name, int mode )
|
||||||
{
|
{
|
||||||
cstring name_narrow = wcs2string(name);
|
cstring name_narrow = wcs2string(name);
|
||||||
return mkdir( name_narrow.c_str(), mode );
|
return mkdir( name_narrow.c_str(), mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
int wrename( const wcstring &old, const wcstring &newv )
|
int wrename( const wcstring &old, const wcstring &newv )
|
||||||
{
|
{
|
||||||
cstring old_narrow = wcs2string(old);
|
cstring old_narrow = wcs2string(old);
|
||||||
cstring new_narrow =wcs2string(newv);
|
cstring new_narrow =wcs2string(newv);
|
||||||
return rename( old_narrow.c_str(), new_narrow.c_str() );
|
return rename( old_narrow.c_str(), new_narrow.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base)
|
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base)
|
||||||
|
|
8
wutil.h
8
wutil.h
|
@ -92,10 +92,10 @@ wchar_t *wgetcwd( wchar_t *buff, size_t sz );
|
||||||
int wchdir( const wcstring &dir );
|
int wchdir( const wcstring &dir );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Wide character version of realpath function. Just like the GNU
|
Wide character version of realpath function. Just like the GNU
|
||||||
version of realpath, wrealpath will accept 0 as the value for the
|
version of realpath, wrealpath will accept 0 as the value for the
|
||||||
second argument, in which case the result will be allocated using
|
second argument, in which case the result will be allocated using
|
||||||
malloc, and must be free'd by the user.
|
malloc, and must be free'd by the user.
|
||||||
*/
|
*/
|
||||||
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path);
|
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path);
|
||||||
|
|
||||||
|
|
126
xdgmime.cpp
126
xdgmime.cpp
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -60,9 +60,9 @@ const char *xdg_mime_type_unknown = "application/octet-stream";
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
XDG_CHECKED_UNCHECKED,
|
XDG_CHECKED_UNCHECKED,
|
||||||
XDG_CHECKED_VALID,
|
XDG_CHECKED_VALID,
|
||||||
XDG_CHECKED_INVALID
|
XDG_CHECKED_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
struct XdgDirTimeList
|
struct XdgDirTimeList
|
||||||
|
@ -86,7 +86,7 @@ struct XdgCallbackList
|
||||||
/* Function called by xdg_run_command_on_dirs. If it returns TRUE, further
|
/* Function called by xdg_run_command_on_dirs. If it returns TRUE, further
|
||||||
* directories aren't looked at */
|
* directories aren't looked at */
|
||||||
typedef int (*XdgDirectoryFunc) (const char *directory,
|
typedef int (*XdgDirectoryFunc) (const char *directory,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
static XdgDirTimeList *
|
static XdgDirTimeList *
|
||||||
xdg_dir_time_list_new (void)
|
xdg_dir_time_list_new (void)
|
||||||
|
@ -172,7 +172,7 @@ xdg_mime_init_from_directory (const char *directory)
|
||||||
/* Runs a command on all the directories in the search path */
|
/* Runs a command on all the directories in the search path */
|
||||||
static void
|
static void
|
||||||
xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
const char *xdg_data_home;
|
const char *xdg_data_home;
|
||||||
const char *xdg_data_dirs;
|
const char *xdg_data_dirs;
|
||||||
|
@ -182,7 +182,7 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
||||||
if (xdg_data_home)
|
if (xdg_data_home)
|
||||||
{
|
{
|
||||||
if ((func) (xdg_data_home, user_data))
|
if ((func) (xdg_data_home, user_data))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -190,19 +190,19 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
||||||
|
|
||||||
home = getenv ("HOME");
|
home = getenv ("HOME");
|
||||||
if (home != NULL)
|
if (home != NULL)
|
||||||
{
|
{
|
||||||
char *guessed_xdg_home;
|
char *guessed_xdg_home;
|
||||||
int stop_processing;
|
int stop_processing;
|
||||||
|
|
||||||
guessed_xdg_home = (char *)malloc (strlen (home) + strlen ("/.local/share/") + 1);
|
guessed_xdg_home = (char *)malloc (strlen (home) + strlen ("/.local/share/") + 1);
|
||||||
strcpy (guessed_xdg_home, home);
|
strcpy (guessed_xdg_home, home);
|
||||||
strcat (guessed_xdg_home, "/.local/share/");
|
strcat (guessed_xdg_home, "/.local/share/");
|
||||||
stop_processing = (func) (guessed_xdg_home, user_data);
|
stop_processing = (func) (guessed_xdg_home, user_data);
|
||||||
free (guessed_xdg_home);
|
free (guessed_xdg_home);
|
||||||
|
|
||||||
if (stop_processing)
|
if (stop_processing)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xdg_data_dirs = getenv ("XDG_DATA_DIRS");
|
xdg_data_dirs = getenv ("XDG_DATA_DIRS");
|
||||||
|
@ -220,18 +220,18 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
||||||
|
|
||||||
end_ptr = ptr;
|
end_ptr = ptr;
|
||||||
while (*end_ptr != ':' && *end_ptr != '\000')
|
while (*end_ptr != ':' && *end_ptr != '\000')
|
||||||
end_ptr ++;
|
end_ptr ++;
|
||||||
|
|
||||||
if (end_ptr == ptr)
|
if (end_ptr == ptr)
|
||||||
{
|
{
|
||||||
ptr++;
|
ptr++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*end_ptr == ':')
|
if (*end_ptr == ':')
|
||||||
len = end_ptr - ptr;
|
len = end_ptr - ptr;
|
||||||
else
|
else
|
||||||
len = end_ptr - ptr + 1;
|
len = end_ptr - ptr + 1;
|
||||||
dir = (char *)malloc (len + 1);
|
dir = (char *)malloc (len + 1);
|
||||||
strncpy (dir, ptr, len);
|
strncpy (dir, ptr, len);
|
||||||
dir[len] = '\0';
|
dir[len] = '\0';
|
||||||
|
@ -239,7 +239,7 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
|
||||||
free (dir);
|
free (dir);
|
||||||
|
|
||||||
if (stop_processing)
|
if (stop_processing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ptr = end_ptr;
|
ptr = end_ptr;
|
||||||
}
|
}
|
||||||
|
@ -262,18 +262,18 @@ xdg_check_file (const char *file_path)
|
||||||
XdgDirTimeList *list;
|
XdgDirTimeList *list;
|
||||||
|
|
||||||
for (list = dir_time_list; list; list = list->next)
|
for (list = dir_time_list; list; list = list->next)
|
||||||
{
|
{
|
||||||
if (! strcmp (list->directory_name, file_path) &&
|
if (! strcmp (list->directory_name, file_path) &&
|
||||||
st.st_mtime == list->mtime)
|
st.st_mtime == list->mtime)
|
||||||
{
|
{
|
||||||
if (list->checked == XDG_CHECKED_UNCHECKED)
|
if (list->checked == XDG_CHECKED_UNCHECKED)
|
||||||
list->checked = XDG_CHECKED_VALID;
|
list->checked = XDG_CHECKED_VALID;
|
||||||
else if (list->checked == XDG_CHECKED_VALID)
|
else if (list->checked == XDG_CHECKED_VALID)
|
||||||
list->checked = XDG_CHECKED_INVALID;
|
list->checked = XDG_CHECKED_INVALID;
|
||||||
|
|
||||||
return (list->checked != XDG_CHECKED_VALID);
|
return (list->checked != XDG_CHECKED_VALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ xdg_check_file (const char *file_path)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xdg_check_dir (const char *directory,
|
xdg_check_dir (const char *directory,
|
||||||
int *invalid_dir_list)
|
int *invalid_dir_list)
|
||||||
{
|
{
|
||||||
int invalid;
|
int invalid;
|
||||||
char *file_name;
|
char *file_name;
|
||||||
|
@ -326,7 +326,7 @@ xdg_check_dirs (void)
|
||||||
list->checked = XDG_CHECKED_UNCHECKED;
|
list->checked = XDG_CHECKED_UNCHECKED;
|
||||||
|
|
||||||
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
|
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
|
||||||
&invalid_dir_list);
|
&invalid_dir_list);
|
||||||
|
|
||||||
if (invalid_dir_list)
|
if (invalid_dir_list)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -334,7 +334,7 @@ xdg_check_dirs (void)
|
||||||
for (list = dir_time_list; list; list = list->next)
|
for (list = dir_time_list; list; list = list->next)
|
||||||
{
|
{
|
||||||
if (list->checked != XDG_CHECKED_VALID)
|
if (list->checked != XDG_CHECKED_VALID)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -381,7 +381,7 @@ xdg_mime_init (void)
|
||||||
parent_list = _xdg_mime_parent_list_new ();
|
parent_list = _xdg_mime_parent_list_new ();
|
||||||
|
|
||||||
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
|
xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
need_reread = FALSE;
|
need_reread = FALSE;
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ xdg_mime_init (void)
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
xdg_mime_get_mime_type_for_data (const void *data,
|
xdg_mime_get_mime_type_for_data (const void *data,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
const char *mime_type;
|
const char *mime_type;
|
||||||
|
|
||||||
|
@ -520,9 +520,9 @@ xdg_mime_shutdown (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if( parent_list )
|
if( parent_list )
|
||||||
{
|
{
|
||||||
_xdg_mime_parent_list_free ( parent_list);
|
_xdg_mime_parent_list_free ( parent_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (list = callback_list; list; list = list->next)
|
for (list = callback_list; list; list = list->next)
|
||||||
|
@ -554,7 +554,7 @@ xdg_mime_unalias_mime_type (const char *mime_type)
|
||||||
|
|
||||||
int
|
int
|
||||||
xdg_mime_mime_type_equal (const char *mime_a,
|
xdg_mime_mime_type_equal (const char *mime_a,
|
||||||
const char *mime_b)
|
const char *mime_b)
|
||||||
{
|
{
|
||||||
const char *unalias_a, *unalias_b;
|
const char *unalias_a, *unalias_b;
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ xdg_mime_mime_type_equal (const char *mime_a,
|
||||||
|
|
||||||
int
|
int
|
||||||
xdg_mime_media_type_equal (const char *mime_a,
|
xdg_mime_media_type_equal (const char *mime_a,
|
||||||
const char *mime_b)
|
const char *mime_b)
|
||||||
{
|
{
|
||||||
char *sep;
|
char *sep;
|
||||||
|
|
||||||
|
@ -604,7 +604,7 @@ xdg_mime_is_super_type (const char *mime)
|
||||||
|
|
||||||
int
|
int
|
||||||
xdg_mime_mime_type_subclass (const char *mime,
|
xdg_mime_mime_type_subclass (const char *mime,
|
||||||
const char *base)
|
const char *base)
|
||||||
{
|
{
|
||||||
const char *umime, *ubase;
|
const char *umime, *ubase;
|
||||||
const char **parents;
|
const char **parents;
|
||||||
|
@ -636,7 +636,7 @@ xdg_mime_mime_type_subclass (const char *mime,
|
||||||
for (; parents && *parents; parents++)
|
for (; parents && *parents; parents++)
|
||||||
{
|
{
|
||||||
if (xdg_mime_mime_type_subclass (*parents, ubase))
|
if (xdg_mime_mime_type_subclass (*parents, ubase))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -668,8 +668,8 @@ xdg_mime_dump (void)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xdg_mime_register_reload_callback (XdgMimeCallback callback,
|
xdg_mime_register_reload_callback (XdgMimeCallback callback,
|
||||||
void *data,
|
void *data,
|
||||||
XdgMimeDestroy destroy)
|
XdgMimeDestroy destroy)
|
||||||
{
|
{
|
||||||
XdgCallbackList *list_el;
|
XdgCallbackList *list_el;
|
||||||
static int callback_id = 1;
|
static int callback_id = 1;
|
||||||
|
@ -698,19 +698,19 @@ xdg_mime_remove_callback (int callback_id)
|
||||||
for (list = callback_list; list; list = list->next)
|
for (list = callback_list; list; list = list->next)
|
||||||
{
|
{
|
||||||
if (list->callback_id == callback_id)
|
if (list->callback_id == callback_id)
|
||||||
{
|
{
|
||||||
if (list->next)
|
if (list->next)
|
||||||
list->next = list->prev;
|
list->next = list->prev;
|
||||||
|
|
||||||
if (list->prev)
|
if (list->prev)
|
||||||
list->prev->next = list->next;
|
list->prev->next = list->next;
|
||||||
else
|
else
|
||||||
callback_list = list->next;
|
callback_list = list->next;
|
||||||
|
|
||||||
/* invoke the destroy handler */
|
/* invoke the destroy handler */
|
||||||
(list->destroy) (list->data);
|
(list->destroy) (list->data);
|
||||||
free (list);
|
free (list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
xdgmime.h
18
xdgmime.h
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -66,24 +66,24 @@ extern const char *xdg_mime_type_unknown;
|
||||||
#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
|
#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
|
||||||
|
|
||||||
const char *xdg_mime_get_mime_type_for_data (const void *data,
|
const char *xdg_mime_get_mime_type_for_data (const void *data,
|
||||||
size_t len);
|
size_t len);
|
||||||
const char *xdg_mime_get_mime_type_for_file (const char *file_name);
|
const char *xdg_mime_get_mime_type_for_file (const char *file_name);
|
||||||
const char *xdg_mime_get_mime_type_from_file_name (const char *file_name);
|
const char *xdg_mime_get_mime_type_from_file_name (const char *file_name);
|
||||||
int xdg_mime_is_valid_mime_type (const char *mime_type);
|
int xdg_mime_is_valid_mime_type (const char *mime_type);
|
||||||
int xdg_mime_mime_type_equal (const char *mime_a,
|
int xdg_mime_mime_type_equal (const char *mime_a,
|
||||||
const char *mime_b);
|
const char *mime_b);
|
||||||
int xdg_mime_media_type_equal (const char *mime_a,
|
int xdg_mime_media_type_equal (const char *mime_a,
|
||||||
const char *mime_b);
|
const char *mime_b);
|
||||||
int xdg_mime_mime_type_subclass (const char *mime_a,
|
int xdg_mime_mime_type_subclass (const char *mime_a,
|
||||||
const char *mime_b);
|
const char *mime_b);
|
||||||
const char **xdg_mime_get_mime_parents (const char *mime);
|
const char **xdg_mime_get_mime_parents (const char *mime);
|
||||||
const char *xdg_mime_unalias_mime_type (const char *mime);
|
const char *xdg_mime_unalias_mime_type (const char *mime);
|
||||||
int xdg_mime_get_max_buffer_extents (void);
|
int xdg_mime_get_max_buffer_extents (void);
|
||||||
void xdg_mime_shutdown (void);
|
void xdg_mime_shutdown (void);
|
||||||
void xdg_mime_dump (void);
|
void xdg_mime_dump (void);
|
||||||
int xdg_mime_register_reload_callback (XdgMimeCallback callback,
|
int xdg_mime_register_reload_callback (XdgMimeCallback callback,
|
||||||
void *data,
|
void *data,
|
||||||
XdgMimeDestroy destroy);
|
XdgMimeDestroy destroy);
|
||||||
void xdg_mime_remove_callback (int callback_id);
|
void xdg_mime_remove_callback (int callback_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -37,12 +37,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct XdgAlias XdgAlias;
|
typedef struct XdgAlias XdgAlias;
|
||||||
|
@ -80,10 +80,10 @@ _xdg_mime_alias_list_free (XdgAliasList *list)
|
||||||
if (list->aliases)
|
if (list->aliases)
|
||||||
{
|
{
|
||||||
for (i = 0; i < list->n_aliases; i++)
|
for (i = 0; i < list->n_aliases; i++)
|
||||||
{
|
{
|
||||||
free (list->aliases[i].alias);
|
free (list->aliases[i].alias);
|
||||||
free (list->aliases[i].mime_type);
|
free (list->aliases[i].mime_type);
|
||||||
}
|
}
|
||||||
free (list->aliases);
|
free (list->aliases);
|
||||||
}
|
}
|
||||||
free (list);
|
free (list);
|
||||||
|
@ -97,7 +97,7 @@ alias_entry_cmp (const void *v1, const void *v2)
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
_xdg_mime_alias_list_lookup (XdgAliasList *list,
|
_xdg_mime_alias_list_lookup (XdgAliasList *list,
|
||||||
const char *alias)
|
const char *alias)
|
||||||
{
|
{
|
||||||
XdgAlias *entry;
|
XdgAlias *entry;
|
||||||
XdgAlias key;
|
XdgAlias key;
|
||||||
|
@ -108,7 +108,7 @@ _xdg_mime_alias_list_lookup (XdgAliasList *list,
|
||||||
key.mime_type = 0;
|
key.mime_type = 0;
|
||||||
|
|
||||||
entry = (XdgAlias *)bsearch (&key, list->aliases, list->n_aliases,
|
entry = (XdgAlias *)bsearch (&key, list->aliases, list->n_aliases,
|
||||||
sizeof (XdgAlias), alias_entry_cmp);
|
sizeof (XdgAlias), alias_entry_cmp);
|
||||||
if (entry)
|
if (entry)
|
||||||
return entry->mime_type;
|
return entry->mime_type;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ _xdg_mime_alias_list_lookup (XdgAliasList *list,
|
||||||
|
|
||||||
void
|
void
|
||||||
_xdg_mime_alias_read_from_file (XdgAliasList *list,
|
_xdg_mime_alias_read_from_file (XdgAliasList *list,
|
||||||
const char *file_name)
|
const char *file_name)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char line[255];
|
char line[255];
|
||||||
|
@ -138,25 +138,25 @@ _xdg_mime_alias_read_from_file (XdgAliasList *list,
|
||||||
{
|
{
|
||||||
char *sep;
|
char *sep;
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sep = strchr (line, ' ');
|
sep = strchr (line, ' ');
|
||||||
if (sep == NULL)
|
if (sep == NULL)
|
||||||
continue;
|
continue;
|
||||||
*(sep++) = '\000';
|
*(sep++) = '\000';
|
||||||
sep[strlen (sep) -1] = '\000';
|
sep[strlen (sep) -1] = '\000';
|
||||||
if (list->n_aliases == alloc)
|
if (list->n_aliases == alloc)
|
||||||
{
|
{
|
||||||
alloc <<= 1;
|
alloc <<= 1;
|
||||||
list->aliases = (XdgAlias *)realloc (list->aliases,
|
list->aliases = (XdgAlias *)realloc (list->aliases,
|
||||||
alloc * sizeof (XdgAlias));
|
alloc * sizeof (XdgAlias));
|
||||||
}
|
}
|
||||||
list->aliases[list->n_aliases].alias = strdup (line);
|
list->aliases[list->n_aliases].alias = strdup (line);
|
||||||
list->aliases[list->n_aliases].mime_type = strdup (sep);
|
list->aliases[list->n_aliases].mime_type = strdup (sep);
|
||||||
list->n_aliases++;
|
list->n_aliases++;
|
||||||
}
|
}
|
||||||
list->aliases = (XdgAlias *)realloc (list->aliases,
|
list->aliases = (XdgAlias *)realloc (list->aliases,
|
||||||
list->n_aliases * sizeof (XdgAlias));
|
list->n_aliases * sizeof (XdgAlias));
|
||||||
|
|
||||||
fclose (file);
|
fclose (file);
|
||||||
|
|
||||||
|
@ -174,11 +174,11 @@ _xdg_mime_alias_list_dump (XdgAliasList *list)
|
||||||
if (list->aliases)
|
if (list->aliases)
|
||||||
{
|
{
|
||||||
for (i = 0; i < list->n_aliases; i++)
|
for (i = 0; i < list->n_aliases; i++)
|
||||||
{
|
{
|
||||||
printf ("%s %s\n",
|
printf ("%s %s\n",
|
||||||
list->aliases[i].alias,
|
list->aliases[i].alias,
|
||||||
list->aliases[i].mime_type);
|
list->aliases[i].mime_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -40,11 +40,11 @@ typedef struct XdgAliasList XdgAliasList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void _xdg_mime_alias_read_from_file (XdgAliasList *list,
|
void _xdg_mime_alias_read_from_file (XdgAliasList *list,
|
||||||
const char *file_name);
|
const char *file_name);
|
||||||
XdgAliasList *_xdg_mime_alias_list_new (void);
|
XdgAliasList *_xdg_mime_alias_list_new (void);
|
||||||
void _xdg_mime_alias_list_free (XdgAliasList *list);
|
void _xdg_mime_alias_list_free (XdgAliasList *list);
|
||||||
const char *_xdg_mime_alias_list_lookup (XdgAliasList *list,
|
const char *_xdg_mime_alias_list_lookup (XdgAliasList *list,
|
||||||
const char *alias);
|
const char *alias);
|
||||||
void _xdg_mime_alias_list_dump (XdgAliasList *list);
|
void _xdg_mime_alias_list_dump (XdgAliasList *list);
|
||||||
|
|
||||||
#endif /* __XDG_MIME_ALIAS_H__ */
|
#endif /* __XDG_MIME_ALIAS_H__ */
|
||||||
|
|
120
xdgmimeglob.cpp
120
xdgmimeglob.cpp
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -37,12 +37,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct XdgGlobHashNode XdgGlobHashNode;
|
typedef struct XdgGlobHashNode XdgGlobHashNode;
|
||||||
|
@ -95,9 +95,9 @@ _xdg_glob_list_free (XdgGlobList *glob_list)
|
||||||
next = ptr->next;
|
next = ptr->next;
|
||||||
|
|
||||||
if (ptr->data)
|
if (ptr->data)
|
||||||
free ((void *) ptr->data);
|
free ((void *) ptr->data);
|
||||||
if (ptr->mime_type)
|
if (ptr->mime_type)
|
||||||
free ((void *) ptr->mime_type);
|
free ((void *) ptr->mime_type);
|
||||||
free (ptr);
|
free (ptr);
|
||||||
|
|
||||||
ptr = next;
|
ptr = next;
|
||||||
|
@ -106,8 +106,8 @@ _xdg_glob_list_free (XdgGlobList *glob_list)
|
||||||
|
|
||||||
static XdgGlobList *
|
static XdgGlobList *
|
||||||
_xdg_glob_list_append (XdgGlobList *glob_list,
|
_xdg_glob_list_append (XdgGlobList *glob_list,
|
||||||
void *data,
|
void *data,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
{
|
{
|
||||||
XdgGlobList *new_element;
|
XdgGlobList *new_element;
|
||||||
XdgGlobList *tmp_element;
|
XdgGlobList *tmp_element;
|
||||||
|
@ -130,8 +130,8 @@ _xdg_glob_list_append (XdgGlobList *glob_list,
|
||||||
#if 0
|
#if 0
|
||||||
static XdgGlobList *
|
static XdgGlobList *
|
||||||
_xdg_glob_list_prepend (XdgGlobList *glob_list,
|
_xdg_glob_list_prepend (XdgGlobList *glob_list,
|
||||||
void *data,
|
void *data,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
{
|
{
|
||||||
XdgGlobList *new_element;
|
XdgGlobList *new_element;
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ _xdg_glob_hash_node_new (void)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
|
_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < depth; i++)
|
for (i = 0; i < depth; i++)
|
||||||
|
@ -178,8 +178,8 @@ _xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
|
||||||
|
|
||||||
static XdgGlobHashNode *
|
static XdgGlobHashNode *
|
||||||
_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
|
_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
|
||||||
const char *text,
|
const char *text,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
{
|
{
|
||||||
XdgGlobHashNode *node;
|
XdgGlobHashNode *node;
|
||||||
xdg_unichar_t character;
|
xdg_unichar_t character;
|
||||||
|
@ -209,33 +209,33 @@ _xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
|
||||||
node = prev_node->next;
|
node = prev_node->next;
|
||||||
|
|
||||||
while (node != NULL)
|
while (node != NULL)
|
||||||
{
|
{
|
||||||
if (character < node->character)
|
if (character < node->character)
|
||||||
{
|
{
|
||||||
node = _xdg_glob_hash_node_new ();
|
node = _xdg_glob_hash_node_new ();
|
||||||
node->character = character;
|
node->character = character;
|
||||||
node->next = prev_node->next;
|
node->next = prev_node->next;
|
||||||
prev_node->next = node;
|
prev_node->next = node;
|
||||||
|
|
||||||
found_node = TRUE;
|
found_node = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (character == node->character)
|
else if (character == node->character)
|
||||||
{
|
{
|
||||||
found_node = TRUE;
|
found_node = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev_node = node;
|
prev_node = node;
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! found_node)
|
if (! found_node)
|
||||||
{
|
{
|
||||||
node = _xdg_glob_hash_node_new ();
|
node = _xdg_glob_hash_node_new ();
|
||||||
node->character = character;
|
node->character = character;
|
||||||
node->next = prev_node->next;
|
node->next = prev_node->next;
|
||||||
prev_node->next = node;
|
prev_node->next = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text = _xdg_utf8_next_char (text);
|
text = _xdg_utf8_next_char (text);
|
||||||
|
@ -252,8 +252,8 @@ _xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
|
_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
|
||||||
const char *file_name,
|
const char *file_name,
|
||||||
int ignore_case)
|
int ignore_case)
|
||||||
{
|
{
|
||||||
XdgGlobHashNode *node;
|
XdgGlobHashNode *node;
|
||||||
xdg_unichar_t character;
|
xdg_unichar_t character;
|
||||||
|
@ -268,22 +268,22 @@ _xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
|
||||||
for (node = glob_hash_node; node && character >= node->character; node = node->next)
|
for (node = glob_hash_node; node && character >= node->character; node = node->next)
|
||||||
{
|
{
|
||||||
if (character == node->character)
|
if (character == node->character)
|
||||||
{
|
{
|
||||||
file_name = _xdg_utf8_next_char (file_name);
|
file_name = _xdg_utf8_next_char (file_name);
|
||||||
if (*file_name == '\000')
|
if (*file_name == '\000')
|
||||||
return node->mime_type;
|
return node->mime_type;
|
||||||
else
|
else
|
||||||
return _xdg_glob_hash_node_lookup_file_name (node->child,
|
return _xdg_glob_hash_node_lookup_file_name (node->child,
|
||||||
file_name,
|
file_name,
|
||||||
ignore_case);
|
ignore_case);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
|
_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
|
||||||
const char *file_name)
|
const char *file_name)
|
||||||
{
|
{
|
||||||
XdgGlobList *list;
|
XdgGlobList *list;
|
||||||
const char *mime_type;
|
const char *mime_type;
|
||||||
|
@ -344,7 +344,7 @@ _xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
|
||||||
if (node->next)
|
if (node->next)
|
||||||
_xdg_glob_hash_free_nodes (node->next);
|
_xdg_glob_hash_free_nodes (node->next);
|
||||||
if (node->mime_type)
|
if (node->mime_type)
|
||||||
free ((void *) node->mime_type);
|
free ((void *) node->mime_type);
|
||||||
free (node);
|
free (node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,9 +370,9 @@ _xdg_glob_determine_type (const char *glob)
|
||||||
while (*ptr != '\000')
|
while (*ptr != '\000')
|
||||||
{
|
{
|
||||||
if (*ptr == '*' && first_char)
|
if (*ptr == '*' && first_char)
|
||||||
maybe_in_simple_glob = TRUE;
|
maybe_in_simple_glob = TRUE;
|
||||||
else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
|
else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
|
||||||
return XDG_GLOB_FULL;
|
return XDG_GLOB_FULL;
|
||||||
|
|
||||||
first_char = FALSE;
|
first_char = FALSE;
|
||||||
ptr = _xdg_utf8_next_char (ptr);
|
ptr = _xdg_utf8_next_char (ptr);
|
||||||
|
@ -386,8 +386,8 @@ _xdg_glob_determine_type (const char *glob)
|
||||||
/* glob must be valid UTF-8 */
|
/* glob must be valid UTF-8 */
|
||||||
void
|
void
|
||||||
_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
|
_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
|
||||||
const char *glob,
|
const char *glob,
|
||||||
const char *mime_type)
|
const char *mime_type)
|
||||||
{
|
{
|
||||||
XdgGlobType type;
|
XdgGlobType type;
|
||||||
|
|
||||||
|
@ -422,7 +422,7 @@ _xdg_glob_hash_dump (XdgGlobHash *glob_hash)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (list = glob_hash->literal_list; list; list = list->next)
|
for (list = glob_hash->literal_list; list; list = list->next)
|
||||||
printf (" %s - %s\n", (char *)list->data, list->mime_type);
|
printf (" %s - %s\n", (char *)list->data, list->mime_type);
|
||||||
}
|
}
|
||||||
printf ("\nSIMPLE GLOBS\n");
|
printf ("\nSIMPLE GLOBS\n");
|
||||||
_xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
|
_xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
|
||||||
|
@ -435,14 +435,14 @@ _xdg_glob_hash_dump (XdgGlobHash *glob_hash)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (list = glob_hash->full_list; list; list = list->next)
|
for (list = glob_hash->full_list; list; list = list->next)
|
||||||
printf (" %s - %s\n", (char *)list->data, list->mime_type);
|
printf (" %s - %s\n", (char *)list->data, list->mime_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
|
_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
|
||||||
const char *file_name)
|
const char *file_name)
|
||||||
{
|
{
|
||||||
FILE *glob_file;
|
FILE *glob_file;
|
||||||
char line[255];
|
char line[255];
|
||||||
|
@ -459,11 +459,11 @@ _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
|
||||||
{
|
{
|
||||||
char *colon;
|
char *colon;
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
colon = strchr (line, ':');
|
colon = strchr (line, ':');
|
||||||
if (colon == NULL)
|
if (colon == NULL)
|
||||||
continue;
|
continue;
|
||||||
*(colon++) = '\000';
|
*(colon++) = '\000';
|
||||||
colon[strlen (colon) -1] = '\000';
|
colon[strlen (colon) -1] = '\000';
|
||||||
_xdg_glob_hash_append_glob (glob_hash, colon, line);
|
_xdg_glob_hash_append_glob (glob_hash, colon, line);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -51,14 +51,14 @@ typedef enum
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
|
void _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
|
||||||
const char *file_name);
|
const char *file_name);
|
||||||
XdgGlobHash *_xdg_glob_hash_new (void);
|
XdgGlobHash *_xdg_glob_hash_new (void);
|
||||||
void _xdg_glob_hash_free (XdgGlobHash *glob_hash);
|
void _xdg_glob_hash_free (XdgGlobHash *glob_hash);
|
||||||
const char *_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
|
const char *_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
|
||||||
const char *text);
|
const char *text);
|
||||||
void _xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
|
void _xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
|
||||||
const char *glob,
|
const char *glob,
|
||||||
const char *mime_type);
|
const char *mime_type);
|
||||||
XdgGlobType _xdg_glob_determine_type (const char *glob);
|
XdgGlobType _xdg_glob_determine_type (const char *glob);
|
||||||
void _xdg_glob_hash_dump (XdgGlobHash *glob_hash);
|
void _xdg_glob_hash_dump (XdgGlobHash *glob_hash);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -33,12 +33,12 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char _xdg_utf8_skip_data[256] = {
|
static const char _xdg_utf8_skip_data[256] = {
|
||||||
|
@ -70,49 +70,49 @@ _xdg_utf8_to_ucs4(const char *source)
|
||||||
int bytelength = 0;
|
int bytelength = 0;
|
||||||
xdg_unichar_t result;
|
xdg_unichar_t result;
|
||||||
if ( ! (*source & 0x40) )
|
if ( ! (*source & 0x40) )
|
||||||
{
|
{
|
||||||
ucs32 = *source;
|
ucs32 = *source;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( ! (*source & 0x20) )
|
if ( ! (*source & 0x20) )
|
||||||
{
|
{
|
||||||
result = *source++ & 0x1F;
|
result = *source++ & 0x1F;
|
||||||
bytelength = 2;
|
bytelength = 2;
|
||||||
}
|
}
|
||||||
else if ( ! (*source & 0x10) )
|
else if ( ! (*source & 0x10) )
|
||||||
{
|
{
|
||||||
result = *source++ & 0x0F;
|
result = *source++ & 0x0F;
|
||||||
bytelength = 3;
|
bytelength = 3;
|
||||||
}
|
}
|
||||||
else if ( ! (*source & 0x08) )
|
else if ( ! (*source & 0x08) )
|
||||||
{
|
{
|
||||||
result = *source++ & 0x07;
|
result = *source++ & 0x07;
|
||||||
bytelength = 4;
|
bytelength = 4;
|
||||||
}
|
}
|
||||||
else if ( ! (*source & 0x04) )
|
else if ( ! (*source & 0x04) )
|
||||||
{
|
{
|
||||||
result = *source++ & 0x03;
|
result = *source++ & 0x03;
|
||||||
bytelength = 5;
|
bytelength = 5;
|
||||||
}
|
}
|
||||||
else if ( ! (*source & 0x02) )
|
else if ( ! (*source & 0x02) )
|
||||||
{
|
{
|
||||||
result = *source++ & 0x01;
|
result = *source++ & 0x01;
|
||||||
bytelength = 6;
|
bytelength = 6;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = *source++;
|
result = *source++;
|
||||||
bytelength = 1;
|
bytelength = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( bytelength --; bytelength > 0; bytelength -- )
|
for ( bytelength --; bytelength > 0; bytelength -- )
|
||||||
{
|
{
|
||||||
result <<= 6;
|
result <<= 6;
|
||||||
result |= *source++ & 0x3F;
|
result |= *source++ & 0x3F;
|
||||||
}
|
}
|
||||||
ucs32 = result;
|
ucs32 = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ucs32;
|
return ucs32;
|
||||||
}
|
}
|
||||||
|
|
18
xdgmimeint.h
18
xdgmimeint.h
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -31,12 +31,12 @@
|
||||||
#include "xdgmime.h"
|
#include "xdgmime.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* FIXME: Needs to be configure check */
|
/* FIXME: Needs to be configure check */
|
||||||
|
@ -55,10 +55,10 @@ typedef unsigned int xdg_uint32_t;
|
||||||
|
|
||||||
#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
|
#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
|
||||||
|
|
||||||
#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) | \
|
#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) | \
|
||||||
(((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) | \
|
(((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) | \
|
||||||
(((xdg_uint32_t)(val) & 0x0000FF00U) << 8) | \
|
(((xdg_uint32_t)(val) & 0x0000FF00U) << 8) | \
|
||||||
(((xdg_uint32_t)(val) & 0x000000FFU) << 24))
|
(((xdg_uint32_t)(val) & 0x000000FFU) << 24))
|
||||||
/* UTF-8 utils
|
/* UTF-8 utils
|
||||||
*/
|
*/
|
||||||
extern const char *const _xdg_utf8_skip;
|
extern const char *const _xdg_utf8_skip;
|
||||||
|
|
360
xdgmimemagic.cpp
360
xdgmimemagic.cpp
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -39,12 +39,12 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int errno;
|
extern int errno;
|
||||||
|
@ -121,11 +121,11 @@ _xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
|
||||||
if (mime_magic_matchlet)
|
if (mime_magic_matchlet)
|
||||||
{
|
{
|
||||||
if (mime_magic_matchlet->next)
|
if (mime_magic_matchlet->next)
|
||||||
_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
|
_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
|
||||||
if (mime_magic_matchlet->value)
|
if (mime_magic_matchlet->value)
|
||||||
free (mime_magic_matchlet->value);
|
free (mime_magic_matchlet->value);
|
||||||
if (mime_magic_matchlet->mask)
|
if (mime_magic_matchlet->mask)
|
||||||
free (mime_magic_matchlet->mask);
|
free (mime_magic_matchlet->mask);
|
||||||
free (mime_magic_matchlet);
|
free (mime_magic_matchlet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,9 +144,9 @@ _xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
|
||||||
next = ptr->next;
|
next = ptr->next;
|
||||||
|
|
||||||
if (ptr->mime_type)
|
if (ptr->mime_type)
|
||||||
free ((void *) ptr->mime_type);
|
free ((void *) ptr->mime_type);
|
||||||
if (ptr->matchlet)
|
if (ptr->matchlet)
|
||||||
_xdg_mime_magic_matchlet_free (ptr->matchlet);
|
_xdg_mime_magic_matchlet_free (ptr->matchlet);
|
||||||
free (ptr);
|
free (ptr);
|
||||||
|
|
||||||
ptr = next;
|
ptr = next;
|
||||||
|
@ -158,7 +158,7 @@ _xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
_xdg_mime_magic_read_to_newline (FILE *magic_file,
|
_xdg_mime_magic_read_to_newline (FILE *magic_file,
|
||||||
int *end_of_file)
|
int *end_of_file)
|
||||||
{
|
{
|
||||||
char *retval;
|
char *retval;
|
||||||
int c;
|
int c;
|
||||||
|
@ -173,18 +173,18 @@ _xdg_mime_magic_read_to_newline (FILE *magic_file,
|
||||||
{
|
{
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
*end_of_file = TRUE;
|
*end_of_file = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c == '\n' || c == '\000')
|
if (c == '\n' || c == '\000')
|
||||||
break;
|
break;
|
||||||
retval[pos++] = (char) c;
|
retval[pos++] = (char) c;
|
||||||
if (pos % 128 == 127)
|
if (pos % 128 == 127)
|
||||||
{
|
{
|
||||||
len = len + 128;
|
len = len + 128;
|
||||||
retval = (char *)realloc (retval, len);
|
retval = (char *)realloc (retval, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retval[pos] = '\000';
|
retval[pos] = '\000';
|
||||||
|
@ -195,7 +195,7 @@ _xdg_mime_magic_read_to_newline (FILE *magic_file,
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
_xdg_mime_magic_read_a_number (FILE *magic_file,
|
_xdg_mime_magic_read_a_number (FILE *magic_file,
|
||||||
int *end_of_file)
|
int *end_of_file)
|
||||||
{
|
{
|
||||||
/* LONG_MAX is about 20 characters on my system */
|
/* LONG_MAX is about 20 characters on my system */
|
||||||
#define MAX_NUMBER_SIZE 30
|
#define MAX_NUMBER_SIZE 30
|
||||||
|
@ -209,19 +209,19 @@ _xdg_mime_magic_read_a_number (FILE *magic_file,
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
|
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
*end_of_file = TRUE;
|
*end_of_file = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (! isdigit (c))
|
if (! isdigit (c))
|
||||||
{
|
{
|
||||||
ungetc (c, magic_file);
|
ungetc (c, magic_file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
number_string[pos] = (char) c;
|
number_string[pos] = (char) c;
|
||||||
pos++;
|
pos++;
|
||||||
if (pos == MAX_NUMBER_SIZE)
|
if (pos == MAX_NUMBER_SIZE)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pos > 0)
|
if (pos > 0)
|
||||||
{
|
{
|
||||||
|
@ -230,7 +230,7 @@ _xdg_mime_magic_read_a_number (FILE *magic_file,
|
||||||
retval = strtol (number_string, NULL, 10);
|
retval = strtol (number_string, NULL, 10);
|
||||||
|
|
||||||
if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
|
if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -297,9 +297,9 @@ _xdg_mime_magic_parse_error (FILE *magic_file)
|
||||||
{
|
{
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
return XDG_MIME_MAGIC_SECTION;
|
return XDG_MIME_MAGIC_SECTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +309,7 @@ _xdg_mime_magic_parse_error (FILE *magic_file)
|
||||||
*/
|
*/
|
||||||
static XdgMimeMagicState
|
static XdgMimeMagicState
|
||||||
_xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
_xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
XdgMimeMagicMatch *match)
|
XdgMimeMagicMatch *match)
|
||||||
{
|
{
|
||||||
XdgMimeMagicMatchlet *matchlet;
|
XdgMimeMagicMatchlet *matchlet;
|
||||||
int c;
|
int c;
|
||||||
|
@ -338,12 +338,12 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
ungetc (c, magic_file);
|
ungetc (c, magic_file);
|
||||||
indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
||||||
if (end_of_file)
|
if (end_of_file)
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
if (indent == -1)
|
if (indent == -1)
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c != '>')
|
if (c != '>')
|
||||||
|
@ -406,9 +406,9 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
if (feof (magic_file))
|
if (feof (magic_file))
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
else
|
else
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
|
@ -417,19 +417,19 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
matchlet->mask = (unsigned char *)malloc (matchlet->value_length);
|
matchlet->mask = (unsigned char *)malloc (matchlet->value_length);
|
||||||
/* OOM */
|
/* OOM */
|
||||||
if (matchlet->mask == NULL)
|
if (matchlet->mask == NULL)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
|
bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
|
||||||
if (bytes_read != matchlet->value_length)
|
if (bytes_read != matchlet->value_length)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
if (feof (magic_file))
|
if (feof (magic_file))
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
else
|
else
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,18 +437,18 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
{
|
{
|
||||||
matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
||||||
if (end_of_file)
|
if (end_of_file)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
}
|
}
|
||||||
if (matchlet->word_size != 0 &&
|
if (matchlet->word_size != 0 &&
|
||||||
matchlet->word_size != 1 &&
|
matchlet->word_size != 1 &&
|
||||||
matchlet->word_size != 2 &&
|
matchlet->word_size != 2 &&
|
||||||
matchlet->word_size != 4)
|
matchlet->word_size != 4)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,15 +456,15 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
{
|
{
|
||||||
matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
|
||||||
if (end_of_file)
|
if (end_of_file)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_EOF;
|
return XDG_MIME_MAGIC_EOF;
|
||||||
}
|
}
|
||||||
if (matchlet->range_length == (unsigned int)-1)
|
if (matchlet->range_length == (unsigned int)-1)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
c = getc_unlocked (magic_file);
|
c = getc_unlocked (magic_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,32 +473,32 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
{
|
{
|
||||||
/* We clean up the matchlet, byte swapping if needed */
|
/* We clean up the matchlet, byte swapping if needed */
|
||||||
if (matchlet->word_size > 1)
|
if (matchlet->word_size > 1)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
if (matchlet->value_length % matchlet->word_size != 0)
|
if (matchlet->value_length % matchlet->word_size != 0)
|
||||||
{
|
{
|
||||||
_xdg_mime_magic_matchlet_free (matchlet);
|
_xdg_mime_magic_matchlet_free (matchlet);
|
||||||
return XDG_MIME_MAGIC_ERROR;
|
return XDG_MIME_MAGIC_ERROR;
|
||||||
}
|
}
|
||||||
/* FIXME: need to get this defined in a <config.h> style file */
|
/* FIXME: need to get this defined in a <config.h> style file */
|
||||||
#if LITTLE_ENDIAN
|
#if LITTLE_ENDIAN
|
||||||
for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
|
for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
|
||||||
{
|
{
|
||||||
if (matchlet->word_size == 2)
|
if (matchlet->word_size == 2)
|
||||||
*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
|
*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
|
||||||
else if (matchlet->word_size == 4)
|
else if (matchlet->word_size == 4)
|
||||||
*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
|
*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
|
||||||
if (matchlet->mask)
|
if (matchlet->mask)
|
||||||
{
|
{
|
||||||
if (matchlet->word_size == 2)
|
if (matchlet->word_size == 2)
|
||||||
*((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
|
*((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
|
||||||
else if (matchlet->word_size == 4)
|
else if (matchlet->word_size == 4)
|
||||||
*((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
|
*((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
matchlet->next = match->matchlet;
|
matchlet->next = match->matchlet;
|
||||||
match->matchlet = matchlet;
|
match->matchlet = matchlet;
|
||||||
|
@ -516,8 +516,8 @@ _xdg_mime_magic_parse_magic_line (FILE *magic_file,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
|
_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
|
||||||
const void *data,
|
const void *data,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
|
@ -526,62 +526,62 @@ _xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
|
||||||
int valid_matchlet = TRUE;
|
int valid_matchlet = TRUE;
|
||||||
|
|
||||||
if (i + matchlet->value_length > len)
|
if (i + matchlet->value_length > len)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (matchlet->mask)
|
if (matchlet->mask)
|
||||||
{
|
{
|
||||||
for (j = 0; j < matchlet->value_length; j++)
|
for (j = 0; j < matchlet->value_length; j++)
|
||||||
{
|
{
|
||||||
if ((matchlet->value[j] & matchlet->mask[j]) !=
|
if ((matchlet->value[j] & matchlet->mask[j]) !=
|
||||||
((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
|
((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
|
||||||
{
|
{
|
||||||
valid_matchlet = FALSE;
|
valid_matchlet = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (j = 0; j < matchlet->value_length; j++)
|
for (j = 0; j < matchlet->value_length; j++)
|
||||||
{
|
{
|
||||||
if (matchlet->value[j] != ((unsigned char *) data)[j + i])
|
if (matchlet->value[j] != ((unsigned char *) data)[j + i])
|
||||||
{
|
{
|
||||||
valid_matchlet = FALSE;
|
valid_matchlet = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (valid_matchlet)
|
if (valid_matchlet)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
|
_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
|
||||||
const void *data,
|
const void *data,
|
||||||
size_t len,
|
size_t len,
|
||||||
int indent)
|
int indent)
|
||||||
{
|
{
|
||||||
while ((matchlet != NULL) && (matchlet->indent == indent))
|
while ((matchlet != NULL) && (matchlet->indent == indent))
|
||||||
{
|
{
|
||||||
if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
|
if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
|
||||||
{
|
{
|
||||||
if ((matchlet->next == NULL) ||
|
if ((matchlet->next == NULL) ||
|
||||||
(matchlet->next->indent <= indent))
|
(matchlet->next->indent <= indent))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
|
if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
|
||||||
data,
|
data,
|
||||||
len,
|
len,
|
||||||
indent + 1))
|
indent + 1))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
matchlet = matchlet->next;
|
matchlet = matchlet->next;
|
||||||
}
|
}
|
||||||
while (matchlet && matchlet->indent > indent);
|
while (matchlet && matchlet->indent > indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,15 +590,15 @@ _xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
|
_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
|
||||||
const void *data,
|
const void *data,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
|
return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_xdg_mime_magic_insert_match (XdgMimeMagic *mime_magic,
|
_xdg_mime_magic_insert_match (XdgMimeMagic *mime_magic,
|
||||||
XdgMimeMagicMatch *match)
|
XdgMimeMagicMatch *match)
|
||||||
{
|
{
|
||||||
XdgMimeMagicMatch *list;
|
XdgMimeMagicMatch *list;
|
||||||
|
|
||||||
|
@ -619,11 +619,11 @@ _xdg_mime_magic_insert_match (XdgMimeMagic *mime_magic,
|
||||||
while (list->next != NULL)
|
while (list->next != NULL)
|
||||||
{
|
{
|
||||||
if (list->next->priority < match->priority)
|
if (list->next->priority < match->priority)
|
||||||
{
|
{
|
||||||
match->next = list->next;
|
match->next = list->next;
|
||||||
list->next = match;
|
list->next = match;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
list = list->next;
|
list = list->next;
|
||||||
}
|
}
|
||||||
list->next = match;
|
list->next = match;
|
||||||
|
@ -653,17 +653,17 @@ _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
|
_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
|
||||||
const void *data,
|
const void *data,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
XdgMimeMagicMatch *match;
|
XdgMimeMagicMatch *match;
|
||||||
|
|
||||||
for (match = mime_magic->match_list; match; match = match->next)
|
for (match = mime_magic->match_list; match; match = match->next)
|
||||||
{
|
{
|
||||||
if (_xdg_mime_magic_match_compare_to_data (match, data, len))
|
if (_xdg_mime_magic_match_compare_to_data (match, data, len))
|
||||||
{
|
{
|
||||||
return match->mime_type;
|
return match->mime_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -680,13 +680,13 @@ _xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
|
||||||
XdgMimeMagicMatchlet *matchlet;
|
XdgMimeMagicMatchlet *matchlet;
|
||||||
|
|
||||||
for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
|
for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
|
||||||
{
|
{
|
||||||
int extent;
|
int extent;
|
||||||
|
|
||||||
extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
|
extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
|
||||||
if (max_extent < extent)
|
if (max_extent < extent)
|
||||||
max_extent = extent;
|
max_extent = extent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mime_magic->max_extent = max_extent;
|
mime_magic->max_extent = max_extent;
|
||||||
|
@ -719,7 +719,7 @@ _xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
|
_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
|
||||||
FILE *magic_file)
|
FILE *magic_file)
|
||||||
{
|
{
|
||||||
XdgMimeMagicState state;
|
XdgMimeMagicState state;
|
||||||
XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
|
XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
|
||||||
|
@ -729,39 +729,39 @@ _xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
|
||||||
while (state != XDG_MIME_MAGIC_EOF)
|
while (state != XDG_MIME_MAGIC_EOF)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case XDG_MIME_MAGIC_SECTION:
|
case XDG_MIME_MAGIC_SECTION:
|
||||||
match = _xdg_mime_magic_match_new ();
|
match = _xdg_mime_magic_match_new ();
|
||||||
state = _xdg_mime_magic_parse_header (magic_file, match);
|
state = _xdg_mime_magic_parse_header (magic_file, match);
|
||||||
if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
|
if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
|
||||||
_xdg_mime_magic_match_free (match);
|
_xdg_mime_magic_match_free (match);
|
||||||
break;
|
break;
|
||||||
case XDG_MIME_MAGIC_MAGIC:
|
case XDG_MIME_MAGIC_MAGIC:
|
||||||
state = _xdg_mime_magic_parse_magic_line (magic_file, match);
|
state = _xdg_mime_magic_parse_magic_line (magic_file, match);
|
||||||
if (state == XDG_MIME_MAGIC_SECTION ||
|
if (state == XDG_MIME_MAGIC_SECTION ||
|
||||||
(state == XDG_MIME_MAGIC_EOF && match->mime_type))
|
(state == XDG_MIME_MAGIC_EOF && match->mime_type))
|
||||||
{
|
{
|
||||||
match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
|
match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
|
||||||
_xdg_mime_magic_insert_match (mime_magic, match);
|
_xdg_mime_magic_insert_match (mime_magic, match);
|
||||||
}
|
}
|
||||||
else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
|
else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
|
||||||
_xdg_mime_magic_match_free (match);
|
_xdg_mime_magic_match_free (match);
|
||||||
break;
|
break;
|
||||||
case XDG_MIME_MAGIC_ERROR:
|
case XDG_MIME_MAGIC_ERROR:
|
||||||
state = _xdg_mime_magic_parse_error (magic_file);
|
state = _xdg_mime_magic_parse_error (magic_file);
|
||||||
break;
|
break;
|
||||||
case XDG_MIME_MAGIC_EOF:
|
case XDG_MIME_MAGIC_EOF:
|
||||||
default:
|
default:
|
||||||
/* Make the compiler happy */
|
/* Make the compiler happy */
|
||||||
assert (0);
|
assert (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_xdg_mime_update_mime_magic_extents (mime_magic);
|
_xdg_mime_update_mime_magic_extents (mime_magic);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
|
_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
|
||||||
const char *file_name)
|
const char *file_name)
|
||||||
{
|
{
|
||||||
FILE *magic_file;
|
FILE *magic_file;
|
||||||
char header[12];
|
char header[12];
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -44,11 +44,11 @@ typedef struct XdgMimeMagic XdgMimeMagic;
|
||||||
|
|
||||||
XdgMimeMagic *_xdg_mime_magic_new (void);
|
XdgMimeMagic *_xdg_mime_magic_new (void);
|
||||||
void _xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
|
void _xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
|
||||||
const char *file_name);
|
const char *file_name);
|
||||||
void _xdg_mime_magic_free (XdgMimeMagic *mime_magic);
|
void _xdg_mime_magic_free (XdgMimeMagic *mime_magic);
|
||||||
int _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
|
int _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
|
||||||
const char *_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
|
const char *_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
|
||||||
const void *data,
|
const void *data,
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
#endif /* __XDG_MIME_MAGIC_H__ */
|
#endif /* __XDG_MIME_MAGIC_H__ */
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -37,12 +37,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (0)
|
#define FALSE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (!FALSE)
|
#define TRUE (!FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct XdgMimeParents XdgMimeParents;
|
typedef struct XdgMimeParents XdgMimeParents;
|
||||||
|
@ -82,13 +82,13 @@ _xdg_mime_parent_list_free (XdgParentList *list)
|
||||||
if (list->parents)
|
if (list->parents)
|
||||||
{
|
{
|
||||||
for (i = 0; i < list->n_mimes; i++)
|
for (i = 0; i < list->n_mimes; i++)
|
||||||
{
|
{
|
||||||
for (p = list->parents[i].parents; *p; p++)
|
for (p = list->parents[i].parents; *p; p++)
|
||||||
free (*p);
|
free (*p);
|
||||||
|
|
||||||
free (list->parents[i].parents);
|
free (list->parents[i].parents);
|
||||||
free (list->parents[i].mime);
|
free (list->parents[i].mime);
|
||||||
}
|
}
|
||||||
free (list->parents);
|
free (list->parents);
|
||||||
}
|
}
|
||||||
free (list);
|
free (list);
|
||||||
|
@ -102,7 +102,7 @@ parent_entry_cmp (const void *v1, const void *v2)
|
||||||
|
|
||||||
const char **
|
const char **
|
||||||
_xdg_mime_parent_list_lookup (XdgParentList *list,
|
_xdg_mime_parent_list_lookup (XdgParentList *list,
|
||||||
const char *mime)
|
const char *mime)
|
||||||
{
|
{
|
||||||
XdgMimeParents *entry;
|
XdgMimeParents *entry;
|
||||||
XdgMimeParents key;
|
XdgMimeParents key;
|
||||||
|
@ -113,7 +113,7 @@ _xdg_mime_parent_list_lookup (XdgParentList *list,
|
||||||
key.parents = NULL;
|
key.parents = NULL;
|
||||||
|
|
||||||
entry = (XdgMimeParents *)bsearch (&key, list->parents, list->n_mimes,
|
entry = (XdgMimeParents *)bsearch (&key, list->parents, list->n_mimes,
|
||||||
sizeof (XdgMimeParents), &parent_entry_cmp);
|
sizeof (XdgMimeParents), &parent_entry_cmp);
|
||||||
if (entry)
|
if (entry)
|
||||||
return (const char **)entry->parents;
|
return (const char **)entry->parents;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ _xdg_mime_parent_list_lookup (XdgParentList *list,
|
||||||
|
|
||||||
void
|
void
|
||||||
_xdg_mime_parent_read_from_file (XdgParentList *list,
|
_xdg_mime_parent_read_from_file (XdgParentList *list,
|
||||||
const char *file_name)
|
const char *file_name)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
char line[255];
|
char line[255];
|
||||||
|
@ -144,54 +144,54 @@ _xdg_mime_parent_read_from_file (XdgParentList *list,
|
||||||
{
|
{
|
||||||
char *sep;
|
char *sep;
|
||||||
if (line[0] == '#')
|
if (line[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sep = strchr (line, ' ');
|
sep = strchr (line, ' ');
|
||||||
if (sep == NULL)
|
if (sep == NULL)
|
||||||
continue;
|
continue;
|
||||||
*(sep++) = '\000';
|
*(sep++) = '\000';
|
||||||
sep[strlen (sep) -1] = '\000';
|
sep[strlen (sep) -1] = '\000';
|
||||||
entry = NULL;
|
entry = NULL;
|
||||||
for (i = 0; i < list->n_mimes; i++)
|
for (i = 0; i < list->n_mimes; i++)
|
||||||
{
|
{
|
||||||
if (strcmp (list->parents[i].mime, line) == 0)
|
if (strcmp (list->parents[i].mime, line) == 0)
|
||||||
{
|
{
|
||||||
entry = &(list->parents[i]);
|
entry = &(list->parents[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
if (list->n_mimes == alloc)
|
if (list->n_mimes == alloc)
|
||||||
{
|
{
|
||||||
alloc <<= 1;
|
alloc <<= 1;
|
||||||
list->parents = (XdgMimeParents *)realloc (list->parents,
|
list->parents = (XdgMimeParents *)realloc (list->parents,
|
||||||
alloc * sizeof (XdgMimeParents));
|
alloc * sizeof (XdgMimeParents));
|
||||||
}
|
}
|
||||||
list->parents[list->n_mimes].mime = strdup (line);
|
list->parents[list->n_mimes].mime = strdup (line);
|
||||||
list->parents[list->n_mimes].parents = NULL;
|
list->parents[list->n_mimes].parents = NULL;
|
||||||
entry = &(list->parents[list->n_mimes]);
|
entry = &(list->parents[list->n_mimes]);
|
||||||
list->n_mimes++;
|
list->n_mimes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entry->parents)
|
if (!entry->parents)
|
||||||
{
|
{
|
||||||
entry->n_parents = 1;
|
entry->n_parents = 1;
|
||||||
entry->parents = (char **)malloc ((entry->n_parents + 1) * sizeof (char *));
|
entry->parents = (char **)malloc ((entry->n_parents + 1) * sizeof (char *));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry->n_parents += 1;
|
entry->n_parents += 1;
|
||||||
entry->parents = (char **)realloc (entry->parents,
|
entry->parents = (char **)realloc (entry->parents,
|
||||||
(entry->n_parents + 2) * sizeof (char *));
|
(entry->n_parents + 2) * sizeof (char *));
|
||||||
}
|
}
|
||||||
entry->parents[entry->n_parents - 1] = strdup (sep);
|
entry->parents[entry->n_parents - 1] = strdup (sep);
|
||||||
entry->parents[entry->n_parents] = NULL;
|
entry->parents[entry->n_parents] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
list->parents = (XdgMimeParents *)realloc (list->parents,
|
list->parents = (XdgMimeParents *)realloc (list->parents,
|
||||||
list->n_mimes * sizeof (XdgMimeParents));
|
list->n_mimes * sizeof (XdgMimeParents));
|
||||||
|
|
||||||
fclose (file);
|
fclose (file);
|
||||||
|
|
||||||
|
@ -210,10 +210,10 @@ _xdg_mime_parent_list_dump (XdgParentList *list)
|
||||||
if (list->parents)
|
if (list->parents)
|
||||||
{
|
{
|
||||||
for (i = 0; i < list->n_mimes; i++)
|
for (i = 0; i < list->n_mimes; i++)
|
||||||
{
|
{
|
||||||
for (p = list->parents[i].parents; *p; p++)
|
for (p = list->parents[i].parents; *p; p++)
|
||||||
printf ("%s %s\n", list->parents[i].mime, *p);
|
printf ("%s %s\n", list->parents[i].mime, *p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
@ -40,11 +40,11 @@ typedef struct XdgParentList XdgParentList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void _xdg_mime_parent_read_from_file (XdgParentList *list,
|
void _xdg_mime_parent_read_from_file (XdgParentList *list,
|
||||||
const char *file_name);
|
const char *file_name);
|
||||||
XdgParentList *_xdg_mime_parent_list_new (void);
|
XdgParentList *_xdg_mime_parent_list_new (void);
|
||||||
void _xdg_mime_parent_list_free (XdgParentList *list);
|
void _xdg_mime_parent_list_free (XdgParentList *list);
|
||||||
const char **_xdg_mime_parent_list_lookup (XdgParentList *list,
|
const char **_xdg_mime_parent_list_lookup (XdgParentList *list,
|
||||||
const char *mime);
|
const char *mime);
|
||||||
void _xdg_mime_parent_list_dump (XdgParentList *list);
|
void _xdg_mime_parent_list_dump (XdgParentList *list);
|
||||||
|
|
||||||
#endif /* __XDG_MIME_PARENT_H__ */
|
#endif /* __XDG_MIME_PARENT_H__ */
|
||||||
|
|
Loading…
Reference in a new issue