Apply new indentation, brace, and whitespace style

This commit is contained in:
ridiculousfish 2012-11-18 16:30:30 -08:00
parent bab69f2672
commit 9992b8eb0e
103 changed files with 32091 additions and 30772 deletions

View file

@ -17,17 +17,24 @@ The classes responsible for autoloading functions and completions.
/* The time before we'll recheck an autoloaded file */
static const int kAutoloadStalenessInterval = 15;
file_access_attempt_t access_file(const wcstring &path, int mode) {
file_access_attempt_t access_file(const wcstring &path, int mode)
{
//printf("Touch %ls\n", path.c_str());
file_access_attempt_t result = {0};
struct stat statbuf;
if (wstat(path, &statbuf)) {
if (wstat(path, &statbuf))
{
result.error = errno;
} else {
}
else
{
result.mod_time = statbuf.st_mtime;
if (waccess(path, mode)) {
if (waccess(path, mode))
{
result.error = errno;
} else {
}
else
{
result.accessible = true;
}
}
@ -39,21 +46,23 @@ file_access_attempt_t access_file(const wcstring &path, int mode) {
}
autoload_t::autoload_t(const wcstring &env_var_name_var, const builtin_script_t * const scripts, size_t script_count) :
lock(),
env_var_name(env_var_name_var),
builtin_scripts(scripts),
builtin_script_count(script_count),
last_path(),
is_loading_set()
lock(),
env_var_name(env_var_name_var),
builtin_scripts(scripts),
builtin_script_count(script_count),
last_path(),
is_loading_set()
{
pthread_mutex_init(&lock, NULL);
}
autoload_t::~autoload_t() {
autoload_t::~autoload_t()
{
pthread_mutex_destroy(&lock);
}
void autoload_t::node_was_evicted(autoload_function_t *node) {
void autoload_t::node_was_evicted(autoload_function_t *node)
{
// This should only ever happen on the main thread
ASSERT_IS_MAIN_THREAD();
@ -63,27 +72,27 @@ void autoload_t::node_was_evicted(autoload_function_t *node) {
delete node;
}
int autoload_t::unload( const wcstring &cmd )
int autoload_t::unload(const wcstring &cmd)
{
return this->evict_node(cmd);
}
int autoload_t::load( const wcstring &cmd, bool reload )
int autoload_t::load(const wcstring &cmd, bool reload)
{
int res;
CHECK_BLOCK( 0 );
int res;
CHECK_BLOCK(0);
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?
*/
if( path_var.empty() )
if (path_var.empty())
return 0;
/* Check if the lookup path has changed. If so, drop all loaded files. path_var may only be inspected on the main thread. */
if( path_var != this->last_path )
if (path_var != this->last_path)
{
this->last_path = path_var;
scoped_lock locker(lock);
@ -93,10 +102,10 @@ int autoload_t::load( const wcstring &cmd, bool reload )
/** Warn and fail on infinite recursion. It's OK to do this because this function is only called on the main thread. */
if (this->is_loading(cmd))
{
debug( 0,
_( L"Could not autoload item '%ls', it is already being autoloaded. "
L"This is a circular dependency in the autoloading scripts, please remove it."),
cmd.c_str() );
debug(0,
_(L"Could not autoload item '%ls', it is already being autoloaded. "
L"This is a circular dependency in the autoloading scripts, please remove it."),
cmd.c_str());
return 1;
}
@ -105,27 +114,27 @@ int autoload_t::load( const wcstring &cmd, bool reload )
/* Get the list of paths from which we will try to load */
std::vector<wcstring> path_list;
tokenize_variable_array( path_var, path_list );
tokenize_variable_array(path_var, path_list);
/* Try loading it */
res = this->locate_file_and_maybe_load_it( cmd, true, reload, path_list );
/* Try loading it */
res = this->locate_file_and_maybe_load_it(cmd, true, reload, path_list);
/* Clean up */
bool erased = !! is_loading_set.erase(cmd);
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)
{
const env_var_t path_var = vars.get(env_var_name);
if (path_var.missing_or_empty())
return false;
std::vector<wcstring> path_list;
tokenize_variable_array( path_var, path_list );
return this->locate_file_and_maybe_load_it( cmd, false, false, path_list );
tokenize_variable_array(path_var, path_list);
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
}
static bool script_name_precedes_script_name(const builtin_script_t &script1, const builtin_script_t &script2)
@ -133,20 +142,22 @@ static bool script_name_precedes_script_name(const builtin_script_t &script1, co
return wcscmp(script1.name, script2.name) < 0;
}
void autoload_t::unload_all(void) {
void autoload_t::unload_all(void)
{
scoped_lock locker(lock);
this->evict_all_nodes();
}
/** Check whether the given command is loaded. */
bool autoload_t::has_tried_loading( const wcstring &cmd )
bool autoload_t::has_tried_loading(const wcstring &cmd)
{
scoped_lock locker(lock);
autoload_function_t * func = this->get_node(cmd);
return func != NULL;
}
static bool is_stale(const autoload_function_t *func) {
static bool is_stale(const autoload_function_t *func)
{
/** Return whether this function is stale. Internalized functions can never be stale. */
return ! func->is_internalized && time(NULL) - func->access.last_checked > kAutoloadStalenessInterval;
}
@ -155,11 +166,15 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
{
ASSERT_IS_LOCKED(lock);
autoload_function_t *func = this->get_node(cmd);
if (! func) {
if (! func)
{
func = new autoload_function_t(cmd);
if (allow_eviction) {
if (allow_eviction)
{
this->add_node(func);
} else {
}
else
{
this->add_node_without_eviction(func);
}
}
@ -178,11 +193,11 @@ autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcs
Result: if really_load is true, returns whether the function was loaded. Otherwise returns whether the function existed.
*/
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! */
size_t i;
bool reloaded = 0;
size_t i;
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. */
{
@ -196,22 +211,30 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
/* Determine if we can use this cached function */
bool use_cached;
if (! func) {
if (! func)
{
/* Can't use a function that doesn't exist */
use_cached = false;
} else if (really_load && ! func->is_placeholder && ! func->is_loaded) {
}
else if (really_load && ! func->is_placeholder && ! func->is_loaded)
{
/* Can't use an unloaded function */
use_cached = false;
} else if ( ! allow_stale_functions && is_stale(func)) {
}
else if (! allow_stale_functions && is_stale(func))
{
/* Can't use a stale function */
use_cached = false;
} else {
}
else
{
/* I guess we can use it */
use_cached = true;
}
/* If we can use this function, return whether we were able to access it */
if (use_cached) {
if (use_cached)
{
return func->is_internalized || func->access.accessible;
}
}
@ -235,7 +258,8 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
matching_builtin_script = found;
}
}
if (matching_builtin_script) {
if (matching_builtin_script)
{
has_script_source = true;
script_source = str2wcstring(matching_builtin_script->def);
@ -253,13 +277,14 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
if (! has_script_source)
{
/* Iterate over path searching for suitable completion files */
for( i=0; i<path_list.size(); i++ )
for (i=0; i<path_list.size(); i++)
{
wcstring next = path_list.at(i);
wcstring path = next + L"/" + cmd + L".fish";
const file_access_attempt_t access = access_file(path, R_OK);
if (access.accessible) {
if (access.accessible)
{
/* Found it! */
found_file = true;
@ -269,7 +294,8 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
/* Generate the source if we need to load it */
bool need_to_load_function = really_load && (func == NULL || func->access.mod_time != access.mod_time || ! func->is_loaded);
if (need_to_load_function) {
if (need_to_load_function)
{
/* Generate the script source */
wcstring esc = escape_string(path, 1);
@ -277,7 +303,8 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
has_script_source = true;
/* Remove any loaded command because we are going to reload it. Note that this will deadlock if command_removed calls back into us. */
if (func && func->is_loaded) {
if (func && func->is_loaded)
{
command_removed(cmd);
func->is_placeholder = false;
}
@ -287,7 +314,8 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
}
/* Create the function if we haven't yet. This does not load it. Do not trigger eviction unless we are actually loading, because we don't want to evict off of the main thread. */
if (! func) {
if (! func)
{
func = get_autoloaded_function_with_creation(cmd, really_load);
}
@ -306,17 +334,21 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
Later we only research if the current time is at least five seconds later.
This way, the files won't be searched over and over again.
*/
if( ! found_file && ! has_script_source )
if (! found_file && ! has_script_source)
{
scoped_lock locker(lock);
/* Generate a placeholder */
autoload_function_t *func = this->get_node(cmd);
if (! func) {
if (! func)
{
func = new autoload_function_t(cmd);
func->is_placeholder = true;
if (really_load) {
if (really_load)
{
this->add_node(func);
} else {
}
else
{
this->add_node_without_eviction(func);
}
}
@ -327,7 +359,7 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
/* If we have a script, either built-in or a file source, then run it */
if (really_load && has_script_source)
{
if( exec_subshell( script_source) == -1 )
if (exec_subshell(script_source) == -1)
{
/*
Do nothing on failiure
@ -336,9 +368,12 @@ bool autoload_t::locate_file_and_maybe_load_it( const wcstring &cmd, bool really
}
if (really_load) {
if (really_load)
{
return reloaded;
} else {
}
else
{
return found_file || has_script_source;
}
}

View file

@ -14,7 +14,8 @@
#include "lru.h"
/** A struct responsible for recording an attempt to access a file. */
struct file_access_attempt_t {
struct file_access_attempt_t
{
time_t mod_time; /** The modification time of the file */
time_t last_checked; /** When we last checked the file */
bool accessible; /** Whether we believe we could access this file */
@ -40,7 +41,8 @@ class env_vars_snapshot_t;
/**
A class that represents a path from which we can autoload, and the autoloaded contents.
*/
class autoload_t : private lru_cache_t<autoload_function_t> {
class autoload_t : private lru_cache_t<autoload_function_t>
{
private:
/** Lock for thread safety */
@ -58,34 +60,36 @@ private:
/** The path from which we most recently autoloaded */
wcstring last_path;
/**
A table containing all the files that are currently being
loaded. This is here to help prevent recursion.
*/
/**
A table containing all the files that are currently being
loaded. This is here to help prevent recursion.
*/
std::set<wcstring> is_loading_set;
bool is_loading(const wcstring &name) const {
bool is_loading(const wcstring &name) const
{
return is_loading_set.find(name) != is_loading_set.end();
}
void remove_all_functions(void) {
void remove_all_functions(void)
{
this->evict_all_nodes();
}
bool locate_file_and_maybe_load_it( const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list );
bool locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list);
virtual void node_was_evicted(autoload_function_t *node);
autoload_function_t *get_autoloaded_function_with_creation(const wcstring &cmd, bool allow_eviction);
protected:
protected:
/** Overridable callback for when a command is removed */
virtual void command_removed(const wcstring &cmd) { }
public:
public:
/** Create an autoload_t for the given environment variable name */
autoload_t(const wcstring &env_var_name_var, const builtin_script_t *scripts, size_t script_count );
autoload_t(const wcstring &env_var_name_var, const builtin_script_t *scripts, size_t script_count);
/** Destructor */
virtual ~autoload_t();
@ -101,10 +105,10 @@ private:
\param on_unload a callback function to run if a suitable file is found, which has not already been run. unload will also be called for old files which are unloaded.
\param reload wheter to recheck file timestamps on already loaded files
*/
int load( const wcstring &cmd, bool reload );
int load(const wcstring &cmd, bool reload);
/** Check whether we have tried loading the given command. Does not do any I/O. */
bool has_tried_loading( const wcstring &cmd );
bool has_tried_loading(const wcstring &cmd);
/**
Tell the autoloader that the specified file, in the specified path,
@ -114,15 +118,15 @@ private:
\param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file.
\return non-zero if the file was removed, zero if the file had not yet been loaded
*/
int unload( const wcstring &cmd );
int unload(const wcstring &cmd);
/**
Unloads all files.
*/
void unload_all( );
void unload_all();
/** Check whether the given command could be loaded, but do not load it. */
bool can_load( const wcstring &cmd, const env_vars_snapshot_t &vars );
bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars);
};

File diff suppressed because it is too large Load diff

View file

@ -15,9 +15,9 @@ class parser_t;
enum
{
COMMAND_NOT_BUILTIN,
BUILTIN_REGULAR,
BUILTIN_FUNCTION
COMMAND_NOT_BUILTIN,
BUILTIN_REGULAR,
BUILTIN_FUNCTION
}
;
@ -125,7 +125,7 @@ void builtin_destroy();
/**
Is there a builtin command with the given name?
*/
int builtin_exists( const wcstring &cmd );
int builtin_exists(const wcstring &cmd);
/**
Execute a builtin command
@ -139,7 +139,7 @@ int builtin_exists( const wcstring &cmd );
\return the exit status of the builtin command
*/
int builtin_run( parser_t &parser, const wchar_t * const *argv, const io_chain_t &io );
int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t &io);
/** Returns a list of all builtin names */
wcstring_list_t builtin_get_names(void);
@ -150,7 +150,7 @@ void builtin_get_names(std::vector<completion_t> &list);
/**
Pushes a new set of input/output to the stack. The new stdin is supplied, a new set of output strings is created.
*/
void builtin_push_io( parser_t &parser, int stdin_fd );
void builtin_push_io(parser_t &parser, int stdin_fd);
/**
Pops a set of input/output from the stack. The output strings are destroued, but the input file is not closed.
@ -161,7 +161,7 @@ void builtin_pop_io(parser_t &parser);
/**
Return a one-line description of the specified builtin.
*/
wcstring builtin_get_desc( const wcstring &b );
wcstring builtin_get_desc(const wcstring &b);
/**
@ -177,6 +177,6 @@ const wchar_t *builtin_complete_get_temporary_buffer();
for the specified command.
*/
wcstring builtin_help_get( parser_t &parser, const wchar_t *cmd );
wcstring builtin_help_get(parser_t &parser, const wchar_t *cmd);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -30,12 +30,12 @@
*/
enum
{
JOBS_DEFAULT, /**< Print lots of general info */
JOBS_PRINT_PID, /**< Print pid of each process in job */
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
JOBS_PRINT_GROUP, /**< Print group id of job */
JOBS_DEFAULT, /**< Print lots of general info */
JOBS_PRINT_PID, /**< Print pid of each process in job */
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
JOBS_PRINT_GROUP, /**< Print group id of job */
}
;
;
@ -43,113 +43,113 @@ enum
/**
Calculates the cpu usage (in percent) of the specified job.
*/
static int cpu_use( const job_t *j )
static int cpu_use(const job_t *j)
{
double u=0;
process_t *p;
double u=0;
process_t *p;
for( p=j->first_process; p; p=p->next )
{
struct timeval t;
int jiffies;
gettimeofday( &t, 0 );
jiffies = proc_get_jiffies( p );
for (p=j->first_process; p; p=p->next)
{
struct timeval t;
int jiffies;
gettimeofday(&t, 0);
jiffies = proc_get_jiffies(p);
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
t1, t2, jiffies, p->last_jiffies );
*/
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
t1, t2, jiffies, p->last_jiffies );
*/
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
}
return u*1000000;
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
}
return u*1000000;
}
#endif
/**
Print information about the specified job
*/
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;
switch( mode )
{
process_t *p;
switch (mode)
{
case JOBS_DEFAULT:
{
if( header )
{
/*
Print table header before first job
*/
stdout_buffer.append( _( L"Job\tGroup\t" ));
if (header)
{
/*
Print table header before first job
*/
stdout_buffer.append(_(L"Job\tGroup\t"));
#ifdef HAVE__PROC_SELF_STAT
stdout_buffer.append( _( L"CPU\t" ) );
stdout_buffer.append(_(L"CPU\t"));
#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
append_format(stdout_buffer, L"%d%%\t", cpu_use(j) );
append_format(stdout_buffer, L"%d%%\t", cpu_use(j));
#endif
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
stdout_buffer.append(L"\t");
stdout_buffer.append(j->command_wcstr());
stdout_buffer.append(L"\n");
break;
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
stdout_buffer.append(L"\t");
stdout_buffer.append(j->command_wcstr());
stdout_buffer.append(L"\n");
break;
}
case JOBS_PRINT_GROUP:
{
if( header )
{
/*
Print table header before first job
*/
stdout_buffer.append( _( L"Group\n" ));
}
append_format(stdout_buffer, L"%d\n", j->pgid );
break;
if (header)
{
/*
Print table header before first job
*/
stdout_buffer.append(_(L"Group\n"));
}
append_format(stdout_buffer, L"%d\n", j->pgid);
break;
}
case JOBS_PRINT_PID:
{
if( header )
{
/*
Print table header before first job
*/
stdout_buffer.append( _( L"Procces\n" ));
}
if (header)
{
/*
Print table header before first job
*/
stdout_buffer.append(_(L"Procces\n"));
}
for( p=j->first_process; p; p=p->next )
{
append_format(stdout_buffer, L"%d\n", p->pid );
}
break;
for (p=j->first_process; p; p=p->next)
{
append_format(stdout_buffer, L"%d\n", p->pid);
}
break;
}
case JOBS_PRINT_COMMAND:
{
if( header )
{
/*
Print table header before first job
*/
stdout_buffer.append( _( L"Command\n" ));
}
if (header)
{
/*
Print table header before first job
*/
stdout_buffer.append(_(L"Command\n"));
}
for( p=j->first_process; p; p=p->next )
{
append_format(stdout_buffer, L"%ls\n", p->argv0() );
}
break;
for (p=j->first_process; p; p=p->next)
{
append_format(stdout_buffer, L"%ls\n", p->argv0());
}
break;
}
}
}
}
@ -158,194 +158,194 @@ static void builtin_jobs_print( const job_t *j, int mode, int header )
/**
The jobs builtin. Used fopr printing running jobs. Defined in builtin_jobs.c.
*/
static int builtin_jobs( parser_t &parser, wchar_t **argv )
static int builtin_jobs(parser_t &parser, wchar_t **argv)
{
int argc=0;
int found=0;
int mode=JOBS_DEFAULT;
int print_last = 0;
const job_t *j;
int argc=0;
int found=0;
int mode=JOBS_DEFAULT;
int print_last = 0;
const job_t *j;
argc = builtin_count_args( argv );
woptind=0;
argc = builtin_count_args(argv);
woptind=0;
while( 1 )
{
static const struct woption
long_options[] =
{
{
L"pid", no_argument, 0, 'p'
}
,
{
L"command", no_argument, 0, 'c'
}
,
{
L"group", no_argument, 0, 'g'
}
,
{
L"last", no_argument, 0, 'l'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = wgetopt_long( argc,
argv,
L"pclgh",
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
while (1)
{
case 0:
if(long_options[opt_index].flag != 0)
break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
static const struct woption
long_options[] =
{
{
L"pid", no_argument, 0, 'p'
}
,
{
L"command", no_argument, 0, 'c'
}
,
{
L"group", no_argument, 0, 'g'
}
,
{
L"last", no_argument, 0, 'l'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
builtin_print_help( parser, argv[0], stderr_buffer );
int opt_index = 0;
int opt = wgetopt_long(argc,
argv,
L"pclgh",
long_options,
&opt_index);
if (opt == -1)
break;
switch (opt)
{
case 0:
if (long_options[opt_index].flag != 0)
break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name);
builtin_print_help(parser, argv[0], stderr_buffer);
return 1;
return 1;
case 'p':
mode=JOBS_PRINT_PID;
break;
case 'p':
mode=JOBS_PRINT_PID;
break;
case 'c':
mode=JOBS_PRINT_COMMAND;
break;
case 'c':
mode=JOBS_PRINT_COMMAND;
break;
case 'g':
mode=JOBS_PRINT_GROUP;
break;
case 'g':
mode=JOBS_PRINT_GROUP;
break;
case 'l':
{
print_last = 1;
break;
}
case 'l':
{
print_last = 1;
break;
}
case 'h':
builtin_print_help( parser, argv[0], stdout_buffer );
return 0;
case 'h':
builtin_print_help(parser, argv[0], stdout_buffer);
return 0;
case '?':
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
return 1;
case '?':
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
return 1;
}
}
}
/*
Do not babble if not interactive
*/
if( builtin_out_redirect )
{
found=1;
}
if( print_last )
{
/*
Ignore unconstructed jobs, i.e. ourself.
Do not babble if not interactive
*/
if (builtin_out_redirect)
{
found=1;
}
if (print_last)
{
/*
Ignore unconstructed jobs, i.e. ourself.
*/
job_iterator_t jobs;
const job_t *j;
while ((j = jobs.next()))
{
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
{
builtin_jobs_print( j, mode, !found );
return 0;
}
}
}
else
{
if( woptind < argc )
{
int i;
found = 1;
for( i=woptind; i<argc; i++ )
{
int pid;
wchar_t *end;
errno=0;
pid=fish_wcstoi( argv[i], &end, 10 );
if( errno || *end )
{
append_format(stderr_buffer,
_( L"%ls: '%ls' is not a job\n" ),
argv[0],
argv[i] );
return 1;
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
{
builtin_jobs_print(j, mode, !found);
return 0;
}
}
j = job_get_from_pid( pid );
if( j && !job_is_completed( j ) )
{
builtin_jobs_print( j, mode, !found );
}
else
{
append_format(stderr_buffer,
_( L"%ls: No suitable job: %d\n" ),
argv[0],
pid );
return 1;
}
}
}
else
{
if (woptind < argc)
{
int i;
found = 1;
for (i=woptind; i<argc; i++)
{
int pid;
wchar_t *end;
errno=0;
pid=fish_wcstoi(argv[i], &end, 10);
if (errno || *end)
{
append_format(stderr_buffer,
_(L"%ls: '%ls' is not a job\n"),
argv[0],
argv[i]);
return 1;
}
j = job_get_from_pid(pid);
if (j && !job_is_completed(j))
{
builtin_jobs_print(j, mode, !found);
}
else
{
append_format(stderr_buffer,
_(L"%ls: No suitable job: %d\n"),
argv[0],
pid);
return 1;
}
}
}
else
{
job_iterator_t jobs;
const job_t *j;
while ((j = jobs.next()))
{
/*
Ignore unconstructed jobs, i.e. ourself.
*/
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
{
builtin_jobs_print( j, mode, !found );
found = 1;
/*
Ignore unconstructed jobs, i.e. ourself.
*/
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
{
builtin_jobs_print(j, mode, !found);
found = 1;
}
}
}
}
}
}
if( !found )
{
append_format(stdout_buffer,
_( L"%ls: There are no jobs\n" ),
argv[0] );
}
if (!found)
{
append_format(stdout_buffer,
_(L"%ls: There are no jobs\n"),
argv[0]);
}
return 0;
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -27,99 +27,99 @@ Functions used for implementing the ulimit builtin.
*/
struct resource_t
{
/**
Resource id
*/
int resource;
/**
Description of resource
*/
const wchar_t *desc;
/**
Switch used on commandline to specify resource
*/
wchar_t switch_char;
/**
The implicit multiplier used when setting getting values
*/
int multiplier;
/**
Resource id
*/
int resource;
/**
Description of resource
*/
const wchar_t *desc;
/**
Switch used on commandline to specify resource
*/
wchar_t switch_char;
/**
The implicit multiplier used when setting getting values
*/
int multiplier;
}
;
;
/**
Array of resource_t structs, describing all known resource types.
*/
static const struct resource_t resource_arr[] =
{
{
RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024
}
,
{
RLIMIT_DATA, L"Maximum size of a processs data segment", L'd', 1024
}
,
{
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
}
,
{
RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024
}
,
{
RLIMIT_DATA, L"Maximum size of a processs data segment", L'd', 1024
}
,
{
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
}
,
#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
#ifdef RLIMIT_RSS
{
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
}
,
{
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
}
,
#endif
{
RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1
}
,
{
RLIMIT_STACK, L"Maximum stack size", L's', 1024
}
,
{
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
}
,
{
RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1
}
,
{
RLIMIT_STACK, L"Maximum stack size", L's', 1024
}
,
{
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
}
,
#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
#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
{
0, 0, 0, 0
}
{
0, 0, 0, 0
}
}
;
;
/**
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++ )
{
if( resource_arr[i].resource == what )
for (i=0; resource_arr[i].desc; i++)
{
return resource_arr[i].multiplier;
if (resource_arr[i].resource == what)
{
return resource_arr[i].multiplier;
}
}
}
return -1;
return -1;
}
/**
@ -127,85 +127,85 @@ static int get_multiplier( int what )
does _not_ multiply the limit value by the multiplier constant used
by the commandline ulimit.
*/
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;
}
/**
Print the value of the specified resource limit
*/
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 )
stdout_buffer.append( L"unlimited\n" );
else
append_format(stdout_buffer, L"%d\n", l / get_multiplier( resource ) );
if (l == RLIM_INFINITY)
stdout_buffer.append(L"unlimited\n");
else
append_format(stdout_buffer, L"%d\n", l / get_multiplier(resource));
}
/**
Print values of all resource limits
*/
static void print_all( int hard )
static void print_all(int hard)
{
int i;
int w=0;
int i;
int w=0;
for( i=0; resource_arr[i].desc; i++ )
{
w=maxi( w, my_wcswidth(resource_arr[i].desc));
}
for( i=0; resource_arr[i].desc; i++ )
{
struct rlimit ls;
rlim_t l;
getrlimit( resource_arr[i].resource, &ls );
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, "));
append_format(stdout_buffer,
L"%-*ls %10ls-%lc) ",
w,
resource_arr[i].desc,
unit,
resource_arr[i].switch_char);
if( l == RLIM_INFINITY )
for (i=0; resource_arr[i].desc; i++)
{
stdout_buffer.append( L"unlimited\n" );
w=maxi(w, my_wcswidth(resource_arr[i].desc));
}
else
for (i=0; resource_arr[i].desc; i++)
{
append_format(stdout_buffer, L"%d\n", l/get_multiplier(resource_arr[i].resource) );
struct rlimit ls;
rlim_t l;
getrlimit(resource_arr[i].resource, &ls);
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, "));
append_format(stdout_buffer,
L"%-*ls %10ls-%lc) ",
w,
resource_arr[i].desc,
unit,
resource_arr[i].switch_char);
if (l == RLIM_INFINITY)
{
stdout_buffer.append(L"unlimited\n");
}
else
{
append_format(stdout_buffer, L"%d\n", l/get_multiplier(resource_arr[i].resource));
}
}
}
}
/**
Returns the description for the specified resource limit
*/
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++ )
{
if( resource_arr[i].resource == what )
for (i=0; resource_arr[i].desc; i++)
{
return resource_arr[i].desc;
if (resource_arr[i].resource == what)
{
return resource_arr[i].desc;
}
}
}
return L"Not a resource";
return L"Not a resource";
}
/**
@ -213,300 +213,300 @@ static const wchar_t *get_desc( int what )
does _not_ multiply the limit value by the multiplier constant used
by the commandline ulimit.
*/
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;
getrlimit( resource, &ls );
struct rlimit ls;
getrlimit(resource, &ls);
if( hard )
{
ls.rlim_max = value;
}
if( soft )
{
ls.rlim_cur = value;
/*
Do not attempt to set the soft limit higher than the hard limit
*/
if( ( value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY ) ||
( value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max))
if (hard)
{
ls.rlim_cur = ls.rlim_max;
ls.rlim_max = value;
}
}
if( setrlimit( resource, &ls ) )
{
if( errno == EPERM )
append_format(stderr_buffer, L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc( resource ) );
else
builtin_wperror( L"ulimit" );
return 1;
}
return 0;
if (soft)
{
ls.rlim_cur = value;
/*
Do not attempt to set the soft limit higher than the hard limit
*/
if ((value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY) ||
(value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max))
{
ls.rlim_cur = ls.rlim_max;
}
}
if (setrlimit(resource, &ls))
{
if (errno == EPERM)
append_format(stderr_buffer, L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc(resource));
else
builtin_wperror(L"ulimit");
return 1;
}
return 0;
}
/**
The ulimit builtin, used for setting resource limits. Defined in
builtin_ulimit.c.
*/
static int builtin_ulimit( parser_t &parser, wchar_t ** argv )
static int builtin_ulimit(parser_t &parser, wchar_t ** argv)
{
int hard=0;
int soft=0;
int hard=0;
int soft=0;
int what = RLIMIT_FSIZE;
int report_all = 0;
int what = RLIMIT_FSIZE;
int report_all = 0;
int argc = builtin_count_args( argv );
int argc = builtin_count_args(argv);
woptind=0;
woptind=0;
while( 1 )
{
static const struct woption
long_options[] =
{
{
L"all", no_argument, 0, 'a'
}
,
{
L"hard", no_argument, 0, 'H'
}
,
{
L"soft", no_argument, 0, 'S'
}
,
{
L"core-size", no_argument, 0, 'c'
}
,
{
L"data-size", no_argument, 0, 'd'
}
,
{
L"file-size", no_argument, 0, 'f'
}
,
{
L"lock-size", no_argument, 0, 'l'
}
,
{
L"resident-set-size", no_argument, 0, 'm'
}
,
{
L"file-descriptor-count", no_argument, 0, 'n'
}
,
{
L"stack-size", no_argument, 0, 's'
}
,
{
L"cpu-time", no_argument, 0, 't'
}
,
{
L"process-count", no_argument, 0, 'u'
}
,
{
L"virtual-memory-size", no_argument, 0, 'v'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = wgetopt_long( argc,
argv,
L"aHScdflmnstuvh",
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
while (1)
{
case 0:
if(long_options[opt_index].flag != 0)
break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
builtin_print_help( parser, argv[0], stderr_buffer );
static const struct woption
long_options[] =
{
{
L"all", no_argument, 0, 'a'
}
,
{
L"hard", no_argument, 0, 'H'
}
,
{
L"soft", no_argument, 0, 'S'
}
,
{
L"core-size", no_argument, 0, 'c'
}
,
{
L"data-size", no_argument, 0, 'd'
}
,
{
L"file-size", no_argument, 0, 'f'
}
,
{
L"lock-size", no_argument, 0, 'l'
}
,
{
L"resident-set-size", no_argument, 0, 'm'
}
,
{
L"file-descriptor-count", no_argument, 0, 'n'
}
,
{
L"stack-size", no_argument, 0, 's'
}
,
{
L"cpu-time", no_argument, 0, 't'
}
,
{
L"process-count", no_argument, 0, 'u'
}
,
{
L"virtual-memory-size", no_argument, 0, 'v'
}
,
{
L"help", no_argument, 0, 'h'
}
,
{
0, 0, 0, 0
}
}
;
return 1;
case L'a':
report_all=1;
break;
int opt_index = 0;
case L'H':
hard=1;
break;
int opt = wgetopt_long(argc,
argv,
L"aHScdflmnstuvh",
long_options,
&opt_index);
if (opt == -1)
break;
case L'S':
soft=1;
break;
switch (opt)
{
case 0:
if (long_options[opt_index].flag != 0)
break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name);
builtin_print_help(parser, argv[0], stderr_buffer);
case L'c':
what=RLIMIT_CORE;
break;
return 1;
case L'd':
what=RLIMIT_DATA;
break;
case L'a':
report_all=1;
break;
case L'f':
what=RLIMIT_FSIZE;
break;
case L'H':
hard=1;
break;
case L'S':
soft=1;
break;
case L'c':
what=RLIMIT_CORE;
break;
case L'd':
what=RLIMIT_DATA;
break;
case L'f':
what=RLIMIT_FSIZE;
break;
#ifdef RLIMIT_MEMLOCK
case L'l':
what=RLIMIT_MEMLOCK;
break;
case L'l':
what=RLIMIT_MEMLOCK;
break;
#endif
#ifdef RLIMIT_RSS
case L'm':
what=RLIMIT_RSS;
break;
case L'm':
what=RLIMIT_RSS;
break;
#endif
case L'n':
what=RLIMIT_NOFILE;
break;
case L'n':
what=RLIMIT_NOFILE;
break;
case L's':
what=RLIMIT_STACK;
break;
case L's':
what=RLIMIT_STACK;
break;
case L't':
what=RLIMIT_CPU;
break;
case L't':
what=RLIMIT_CPU;
break;
#ifdef RLIMIT_NPROC
case L'u':
what=RLIMIT_NPROC;
break;
case L'u':
what=RLIMIT_NPROC;
break;
#endif
#ifdef RLIMIT_AS
case L'v':
what=RLIMIT_AS;
break;
case L'v':
what=RLIMIT_AS;
break;
#endif
case L'h':
builtin_print_help( parser, argv[0], stdout_buffer );
return 0;
case L'h':
builtin_print_help(parser, argv[0], stdout_buffer);
return 0;
case L'?':
builtin_unknown_option( parser, argv[0], argv[woptind-1] );
return 1;
case L'?':
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
return 1;
}
}
}
if( report_all )
{
if( argc - woptind == 0 )
{
print_all( hard );
}
else
if (report_all)
{
if (argc - woptind == 0)
{
print_all(hard);
}
else
{
stderr_buffer.append(argv[0]);
stderr_buffer.append(L": Too many arguments\n");
builtin_print_help( parser, argv[0], stderr_buffer );
return 1;
builtin_print_help(parser, argv[0], stderr_buffer);
return 1;
}
return 0;
}
return 0;
}
switch( argc - woptind )
{
switch (argc - woptind)
{
case 0:
{
/*
Show current limit value
*/
print( what, hard );
break;
/*
Show current limit value
*/
print(what, hard);
break;
}
case 1:
{
/*
Change current limit value
*/
rlim_t new_limit;
wchar_t *end;
/*
Change current limit value
*/
rlim_t new_limit;
wchar_t *end;
/*
Set both hard and soft limits if nothing else was specified
*/
if( !(hard+soft) )
{
hard=soft=1;
}
if( wcscasecmp( argv[woptind], L"unlimited" )==0)
{
new_limit = RLIM_INFINITY;
}
else if( wcscasecmp( argv[woptind], L"hard" )==0)
{
new_limit = get( what, 1 );
}
else if( wcscasecmp( argv[woptind], L"soft" )==0)
{
new_limit = get( what, soft );
}
else
{
errno=0;
new_limit = wcstol( argv[woptind], &end, 10 );
if( errno || *end )
/*
Set both hard and soft limits if nothing else was specified
*/
if (!(hard+soft))
{
append_format(stderr_buffer,
L"%ls: Invalid limit '%ls'\n",
argv[0],
argv[woptind] );
builtin_print_help( parser, argv[0], stderr_buffer );
return 1;
hard=soft=1;
}
new_limit *= get_multiplier( what );
}
return set( what, hard, soft, new_limit );
if (wcscasecmp(argv[woptind], L"unlimited")==0)
{
new_limit = RLIM_INFINITY;
}
else if (wcscasecmp(argv[woptind], L"hard")==0)
{
new_limit = get(what, 1);
}
else if (wcscasecmp(argv[woptind], L"soft")==0)
{
new_limit = get(what, soft);
}
else
{
errno=0;
new_limit = wcstol(argv[woptind], &end, 10);
if (errno || *end)
{
append_format(stderr_buffer,
L"%ls: Invalid limit '%ls'\n",
argv[0],
argv[woptind]);
builtin_print_help(parser, argv[0], stderr_buffer);
return 1;
}
new_limit *= get_multiplier(what);
}
return set(what, hard, soft, new_limit);
}
default:
{
stderr_buffer.append(argv[0]);
stderr_buffer.append(L": Too many arguments\n");
builtin_print_help( parser, argv[0], stderr_buffer );
return 1;
stderr_buffer.append(argv[0]);
stderr_buffer.append(L": Too many arguments\n");
builtin_print_help(parser, argv[0], stderr_buffer);
return 1;
}
}
return 0;
}
return 0;
}

243
color.cpp
View file

@ -4,40 +4,73 @@
#include "color.h"
#include "fallback.h"
bool rgb_color_t::try_parse_special(const wcstring &special) {
bool rgb_color_t::try_parse_special(const wcstring &special)
{
bzero(&data, sizeof data);
const wchar_t *name = special.c_str();
if (! wcscasecmp(name, L"normal")) {
if (! wcscasecmp(name, L"normal"))
{
this->type = type_normal;
} else if (! wcscasecmp(name, L"reset")) {
}
else if (! wcscasecmp(name, L"reset"))
{
this->type = type_reset;
} else if (! wcscasecmp(name, L"ignore")) {
}
else if (! wcscasecmp(name, L"ignore"))
{
this->type = type_ignore;
} else {
}
else
{
this->type = type_none;
}
return this->type != type_none;
}
static int parse_hex_digit(wchar_t x) {
switch (x) {
case L'0': return 0x0;
case L'1': return 0x1;
case L'2': return 0x2;
case L'3': return 0x3;
case L'4': return 0x4;
case L'5': return 0x5;
case L'6': return 0x6;
case L'7': return 0x7;
case L'8': return 0x8;
case L'9': return 0x9;
case L'a':case L'A': return 0xA;
case L'b':case L'B': return 0xB;
case L'c':case L'C': return 0xC;
case L'd':case L'D': return 0xD;
case L'e':case L'E': return 0xE;
case L'f':case L'F': return 0xF;
default: return -1;
static int parse_hex_digit(wchar_t x)
{
switch (x)
{
case L'0':
return 0x0;
case L'1':
return 0x1;
case L'2':
return 0x2;
case L'3':
return 0x3;
case L'4':
return 0x4;
case L'5':
return 0x5;
case L'6':
return 0x6;
case L'7':
return 0x7;
case L'8':
return 0x8;
case L'9':
return 0x9;
case L'a':
case L'A':
return 0xA;
case L'b':
case L'B':
return 0xB;
case L'c':
case L'C':
return 0xC;
case L'd':
case L'D':
return 0xD;
case L'e':
case L'E':
return 0xE;
case L'f':
case L'F':
return 0xF;
default:
return -1;
}
}
@ -47,15 +80,18 @@ static unsigned long squared_difference(long p1, long p2)
return diff * diff;
}
static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *colors, size_t color_count) {
static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *colors, size_t color_count)
{
long r = rgb[0], g = rgb[1], b = rgb[2];
unsigned long best_distance = (unsigned long)(-1);
unsigned char best_index = (unsigned char)(-1);
for (unsigned char idx = 0; idx < color_count; idx++) {
for (unsigned char idx = 0; idx < color_count; idx++)
{
uint32_t color = colors[idx];
long test_r = (color >> 16) & 0xFF, test_g = (color >> 8) & 0xFF, test_b = (color >> 0) & 0xFF;
unsigned long distance = squared_difference(r, test_r) + squared_difference(g, test_g) + squared_difference(b, test_b);
if (distance <= best_distance) {
if (distance <= best_distance)
{
best_index = idx;
best_distance = distance;
}
@ -64,7 +100,8 @@ static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *c
}
bool rgb_color_t::try_parse_rgb(const wcstring &name) {
bool rgb_color_t::try_parse_rgb(const wcstring &name)
{
bzero(&data, sizeof data);
/* We support the following style of rgb formats (case insensitive):
#FA3
@ -81,17 +118,22 @@ bool rgb_color_t::try_parse_rgb(const wcstring &name) {
bool success = false;
size_t i;
if (len - digit_idx == 3) {
if (len - digit_idx == 3)
{
// type FA3
for (i=0; i < 3; i++) {
for (i=0; i < 3; i++)
{
int val = parse_hex_digit(name.at(digit_idx++));
if (val < 0) break;
data.rgb[i] = val*16+val;
}
success = (i == 3);
} else if (len - digit_idx == 6) {
}
else if (len - digit_idx == 6)
{
// type F3A035
for (i=0; i < 3; i++) {
for (i=0; i < 3; i++)
{
int hi = parse_hex_digit(name.at(digit_idx++));
int lo = parse_hex_digit(name.at(digit_idx++));
if (lo < 0 || hi < 0) break;
@ -99,19 +141,22 @@ bool rgb_color_t::try_parse_rgb(const wcstring &name) {
}
success = (i == 3);
}
if (success) {
if (success)
{
this->type = type_rgb;
}
return success;
}
struct named_color_t {
struct named_color_t
{
const wchar_t * name;
unsigned char idx;
unsigned char rgb[3];
};
static const named_color_t named_colors[11] = {
static const named_color_t named_colors[11] =
{
{L"black", 0, {0, 0, 0}},
{L"red", 1, {0xFF, 0, 0}},
{L"green", 2, {0, 0xFF, 0}},
@ -125,11 +170,14 @@ static const named_color_t named_colors[11] = {
{L"normal", 8, {0xFF, 0xFF, 0XFF}}
};
bool rgb_color_t::try_parse_named(const wcstring &str) {
bool rgb_color_t::try_parse_named(const wcstring &str)
{
bzero(&data, sizeof data);
size_t max = sizeof named_colors / sizeof *named_colors;
for (size_t idx=0; idx < max; idx++) {
if (0 == wcscasecmp(str.c_str(), named_colors[idx].name)) {
for (size_t idx=0; idx < max; idx++)
{
if (0 == wcscasecmp(str.c_str(), named_colors[idx].name))
{
data.name_idx = named_colors[idx].idx;
this->type = type_named;
return true;
@ -138,29 +186,53 @@ bool rgb_color_t::try_parse_named(const wcstring &str) {
return false;
}
static const wchar_t *name_for_color_idx(unsigned char idx) {
static const wchar_t *name_for_color_idx(unsigned char idx)
{
size_t max = sizeof named_colors / sizeof *named_colors;
for (size_t i=0; i < max; i++) {
if (named_colors[i].idx == idx) {
for (size_t i=0; i < max; i++)
{
if (named_colors[i].idx == idx)
{
return named_colors[i].name;
}
}
return L"unknown";
}
rgb_color_t::rgb_color_t(unsigned char t, unsigned char i) : type(t), flags(), data() {
rgb_color_t::rgb_color_t(unsigned char t, unsigned char i) : type(t), flags(), data()
{
data.name_idx = i;
}
rgb_color_t rgb_color_t::normal() { return rgb_color_t(type_normal); }
rgb_color_t rgb_color_t::reset() { return rgb_color_t(type_reset); }
rgb_color_t rgb_color_t::ignore() { return rgb_color_t(type_ignore); }
rgb_color_t rgb_color_t::none() { return rgb_color_t(type_none); }
rgb_color_t rgb_color_t::white() { return rgb_color_t(type_named, 7); }
rgb_color_t rgb_color_t::black() { return rgb_color_t(type_named, 0); }
rgb_color_t rgb_color_t::normal()
{
return rgb_color_t(type_normal);
}
rgb_color_t rgb_color_t::reset()
{
return rgb_color_t(type_reset);
}
rgb_color_t rgb_color_t::ignore()
{
return rgb_color_t(type_ignore);
}
rgb_color_t rgb_color_t::none()
{
return rgb_color_t(type_none);
}
rgb_color_t rgb_color_t::white()
{
return rgb_color_t(type_named, 7);
}
rgb_color_t rgb_color_t::black()
{
return rgb_color_t(type_named, 0);
}
static unsigned char term8_color_for_rgb(const unsigned char rgb[3]) {
const uint32_t kColors[] = {
static unsigned char term8_color_for_rgb(const unsigned char rgb[3])
{
const uint32_t kColors[] =
{
0x000000, //Black
0xFF0000, //Red
0x00FF00, //Green
@ -173,8 +245,10 @@ static unsigned char term8_color_for_rgb(const unsigned char rgb[3]) {
return convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
}
static unsigned char term256_color_for_rgb(const unsigned char rgb[3]) {
const uint32_t kColors[240] = {
static unsigned char term256_color_for_rgb(const unsigned char rgb[3])
{
const uint32_t kColors[240] =
{
0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
@ -209,58 +283,71 @@ static unsigned char term256_color_for_rgb(const unsigned char rgb[3]) {
return 16 + convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
}
unsigned char rgb_color_t::to_term256_index() const {
unsigned char rgb_color_t::to_term256_index() const
{
assert(type == type_rgb);
return term256_color_for_rgb(data.rgb);
}
unsigned char rgb_color_t::to_name_index() const {
unsigned char rgb_color_t::to_name_index() const
{
assert(type == type_named || type == type_rgb);
if (type == type_named) {
if (type == type_named)
{
return data.name_idx;
} else if (type == type_rgb) {
}
else if (type == type_rgb)
{
return term8_color_for_rgb(data.rgb);
} else {
}
else
{
/* This is an error */
return (unsigned char)(-1);
}
}
void rgb_color_t::parse(const wcstring &str) {
void rgb_color_t::parse(const wcstring &str)
{
bool success = false;
if (! success) success = try_parse_special(str);
if (! success) success = try_parse_named(str);
if (! success) success = try_parse_rgb(str);
if (! success) {
if (! success)
{
bzero(this->data.rgb, sizeof this->data.rgb);
this->type = type_none;
}
}
rgb_color_t::rgb_color_t(const wcstring &str) {
rgb_color_t::rgb_color_t(const wcstring &str)
{
this->parse(str);
}
rgb_color_t::rgb_color_t(const std::string &str) {
rgb_color_t::rgb_color_t(const std::string &str)
{
this->parse(str2wcstring(str));
}
wcstring rgb_color_t::description() const {
switch (type) {
case type_none:
return L"none";
case type_named:
return format_string(L"named(%d: %ls)", (int)data.name_idx, name_for_color_idx(data.name_idx));
case type_rgb:
return format_string(L"rgb(0x%02x%02x%02x)", data.rgb[0], data.rgb[1], data.rgb[2]);
case type_reset:
return L"reset";
case type_normal:
return L"normal";
case type_ignore:
return L"ignore";
default:
abort();
return L"";
wcstring rgb_color_t::description() const
{
switch (type)
{
case type_none:
return L"none";
case type_named:
return format_string(L"named(%d: %ls)", (int)data.name_idx, name_for_color_idx(data.name_idx));
case type_rgb:
return format_string(L"rgb(0x%02x%02x%02x)", data.rgb[0], data.rgb[1], data.rgb[2]);
case type_reset:
return L"reset";
case type_normal:
return L"normal";
case type_ignore:
return L"ignore";
default:
abort();
return L"";
}
}

77
color.h
View file

@ -10,10 +10,12 @@
/* A type that represents a color. We work hard to keep it at a size of 4 bytes. */
class rgb_color_t {
class rgb_color_t
{
/* Types */
enum {
enum
{
type_none,
type_named,
type_rgb,
@ -24,13 +26,15 @@ class rgb_color_t {
unsigned char type:4;
/* Flags */
enum {
enum
{
flag_bold = 1 << 0,
flag_underline = 1 << 1
};
unsigned char flags:4;
union {
union
{
unsigned char name_idx; //0-10
unsigned char rgb[3];
} data;
@ -50,7 +54,7 @@ class rgb_color_t {
/** Private constructor */
explicit rgb_color_t(unsigned char t, unsigned char i=0);
public:
public:
/** Default constructor of type none */
explicit rgb_color_t() : type(type_none), flags(), data() {}
@ -78,25 +82,46 @@ class rgb_color_t {
static rgb_color_t none();
/** Returns whether the color is the ignore special color */
bool is_ignore(void) const { return type == type_ignore; }
bool is_ignore(void) const
{
return type == type_ignore;
}
/** Returns whether the color is the normal special color */
bool is_normal(void) const { return type == type_normal; }
bool is_normal(void) const
{
return type == type_normal;
}
/** Returns whether the color is the reset special color */
bool is_reset(void) const { return type == type_reset; }
bool is_reset(void) const
{
return type == type_reset;
}
/** Returns whether the color is the none special color */
bool is_none(void) const { return type == type_none; }
bool is_none(void) const
{
return type == type_none;
}
/** Returns whether the color is a named color (like "magenta") */
bool is_named(void) const { return type == type_named; }
bool is_named(void) const
{
return type == type_named;
}
/** Returns whether the color is specified via RGB components */
bool is_rgb(void) const { return type == type_rgb; }
bool is_rgb(void) const
{
return type == type_rgb;
}
/** Returns whether the color is special, that is, not rgb or named */
bool is_special(void) const { return type != type_named && type != type_rgb; }
bool is_special(void) const
{
return type != type_named && type != type_rgb;
}
/** Returns a description of the color */
wcstring description() const;
@ -108,24 +133,40 @@ class rgb_color_t {
unsigned char to_term256_index() const;
/** Returns whether the color is bold */
bool is_bold() const { return flags & flag_bold; }
bool is_bold() const
{
return flags & flag_bold;
}
/** Set whether the color is bold */
void set_bold(bool x) { if (x) flags |= flag_bold; else flags &= ~flag_bold; }
void set_bold(bool x)
{
if (x) flags |= flag_bold;
else flags &= ~flag_bold;
}
/** Returns whether the color is underlined */
bool is_underline() const { return !! (flags & flag_underline); }
bool is_underline() const
{
return !!(flags & flag_underline);
}
/** Set whether the color is underlined */
void set_underline(bool x) { if (x) flags |= flag_underline; else flags &= ~flag_underline; }
void set_underline(bool x)
{
if (x) flags |= flag_underline;
else flags &= ~flag_underline;
}
/** Compare two colors for equality */
bool operator==(const rgb_color_t &other) const {
bool operator==(const rgb_color_t &other) const
{
return type == other.type && ! memcmp(&data, &other.data, sizeof data);
}
/** Compare two colors for inequality */
bool operator!=(const rgb_color_t &other) const {
bool operator!=(const rgb_color_t &other) const
{
return !(*this == other);
}
};

2661
common.cpp

File diff suppressed because it is too large Load diff

264
common.h
View file

@ -64,13 +64,14 @@ typedef std::vector<wcstring> wcstring_list_t;
#define UNESCAPE_INCOMPLETE 2
/* Flags for the escape() and escape_string() functions */
enum {
enum
{
/** Escape all characters, including magic characters like the semicolon */
ESCAPE_ALL = 1 << 0,
ESCAPE_ALL = 1 << 0,
/** Do not try to use 'simplified' quoted escapes, and do not use empty quotes as the empty string */
ESCAPE_NO_QUOTED = 1 << 1,
/** Do not escape tildes */
ESCAPE_NO_TILDE = 1 << 2
};
@ -82,12 +83,12 @@ typedef unsigned int escape_flags_t;
#define VOMIT_ON_FAILURE(a) do { if (0 != (a)) { int err = errno; fprintf(stderr, "%s failed on line %d in file %s: %d (%s)\n", #a, __LINE__, __FILE__, err, strerror(err)); abort(); }} while (0)
/** Exits without invoking destructors (via _exit), useful for code after fork. */
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
*/
extern struct termios shell_modes;
extern struct termios shell_modes;
/**
The character to use where the text has been truncated. Is an
@ -119,7 +120,7 @@ extern const wchar_t *program_name;
parameter is the return value of the current function on failiure.
*/
#define CHECK( arg, retval ) \
if( !(arg) ) \
if (!(arg)) \
{ \
debug( 0, \
"function %s called with null value for argument %s. ", \
@ -140,7 +141,7 @@ extern const wchar_t *program_name;
read( 0, &exit_read_buff, 1 ); \
exit_without_destructors( 1 ); \
} \
/**
Exit program at once, leaving an error message about running out of memory.
@ -158,8 +159,8 @@ extern const wchar_t *program_name;
Check if signals are blocked. If so, print an error message and
return from the function performing this check.
*/
#define CHECK_BLOCK( retval ) \
if( signal_is_blocked() ) \
#define CHECK_BLOCK(retval) \
if (signal_is_blocked()) \
{ \
debug( 0, \
"function %s called while blocking signals. ", \
@ -168,7 +169,7 @@ extern const wchar_t *program_name;
show_stackframe(); \
return retval; \
}
/**
Shorthand for wgettext call
*/
@ -176,7 +177,7 @@ extern const wchar_t *program_name;
/**
Noop, used to tell xgettext that a string should be translated,
even though it is not directly sent to wgettext.
even though it is not directly sent to wgettext.
*/
#define N_(wstr) wstr
@ -192,7 +193,7 @@ void show_stackframe();
/**
Read a line from the stream f into the string. Returns
Read a line from the stream f into the string. Returns
the number of bytes read or -1 on failiure.
If the carriage return character is encountered, it is
@ -209,17 +210,17 @@ int fgetws2(wcstring *s, FILE *f);
This function encodes illegal character sequences in a reversible
way using the private use area.
*/
wchar_t *str2wcs( const char *in );
wchar_t *str2wcs(const char *in);
/**
Returns a newly allocated wide character string equivalent of the
specified multibyte character string
This function encodes illegal character sequences in a reversible
way using the private use area.
*/
wcstring str2wcstring( const char *in );
wcstring str2wcstring( const std::string &in );
wcstring str2wcstring(const char *in);
wcstring str2wcstring(const std::string &in);
/**
Converts the narrow character string \c in into it's wide
@ -229,7 +230,7 @@ wcstring str2wcstring( const std::string &in );
This function encodes illegal character sequences in a reversible
way using the private use area.
*/
wchar_t *str2wcs_internal( const char *in, wchar_t *out );
wchar_t *str2wcs_internal(const char *in, wchar_t *out);
/**
Returns a newly allocated multibyte character string equivalent of
@ -238,7 +239,7 @@ wchar_t *str2wcs_internal( const char *in, wchar_t *out );
This function decodes illegal character sequences in a reversible
way using the private use area.
*/
char *wcs2str( const wchar_t *in );
char *wcs2str(const wchar_t *in);
std::string wcs2string(const wcstring &input);
/** Test if a string prefixes another. Returns true if a is a prefix of b */
@ -277,7 +278,7 @@ void assert_is_locked(void *mutex, const char *who, const char *caller);
This function decodes illegal character sequences in a reversible
way using the private use area.
*/
char *wcs2str_internal( const wchar_t *in, char *out );
char *wcs2str_internal(const wchar_t *in, char *out);
/** Format the specified size (in bytes, kilobytes, etc.) into the specified stringbuffer. */
wcstring format_size(long long sz);
@ -294,7 +295,8 @@ void format_long_safe(wchar_t buff[128], long val);
template<typename T>
T from_string(const wcstring &x) {
T from_string(const wcstring &x)
{
T result;
std::wstringstream stream(x);
stream >> result;
@ -302,7 +304,8 @@ T from_string(const wcstring &x) {
}
template<typename T>
T from_string(const std::string &x) {
T from_string(const std::string &x)
{
T result = T();
std::stringstream stream(x);
stream >> result;
@ -310,7 +313,8 @@ T from_string(const std::string &x) {
}
template<typename T>
wcstring to_string(const T &x) {
wcstring to_string(const T &x)
{
std::wstringstream stream;
stream << x;
return stream.str();
@ -318,86 +322,109 @@ wcstring to_string(const T &x) {
/* wstringstream is a huge memory pig. Let's provide some specializations where we can. */
template<>
inline wcstring to_string(const long &x) {
inline wcstring to_string(const long &x)
{
wchar_t buff[128];
format_long_safe(buff, x);
return wcstring(buff);
}
template<>
inline bool from_string(const std::string &x) {
inline bool from_string(const std::string &x)
{
return ! x.empty() && strchr("YTyt1", x.at(0));
}
template<>
inline bool from_string(const wcstring &x) {
inline bool from_string(const wcstring &x)
{
return ! x.empty() && wcschr(L"YTyt1", x.at(0));
}
template<>
inline wcstring to_string(const int &x) {
inline wcstring to_string(const int &x)
{
return to_string(static_cast<long>(x));
}
/* Helper class for managing a null-terminated array of null-terminated strings (of some char type) */
template <typename CharType_t>
class null_terminated_array_t {
class null_terminated_array_t
{
CharType_t **array;
typedef std::basic_string<CharType_t> string_t;
typedef std::vector<string_t> string_list_t;
void swap(null_terminated_array_t<CharType_t> &him) { std::swap(array, him.array); }
void swap(null_terminated_array_t<CharType_t> &him)
{
std::swap(array, him.array);
}
/* Silly function to get the length of a null terminated array of...something */
template <typename T>
static size_t count_not_null(const T *arr) {
static size_t count_not_null(const T *arr)
{
size_t len;
for (len=0; arr[len] != T(0); len++)
;
return len;
return len;
}
size_t size() const {
size_t size() const
{
return count_not_null(array);
}
void free(void) {
if (array != NULL) {
for (size_t i = 0; array[i] != NULL; i++) {
void free(void)
{
if (array != NULL)
{
for (size_t i = 0; array[i] != NULL; i++)
{
delete [] array[i];
}
delete [] array;
array = NULL;
}
}
public:
public:
null_terminated_array_t() : array(NULL) { }
null_terminated_array_t(const string_list_t &argv) : array(NULL) { this->set(argv); }
~null_terminated_array_t() { this->free(); }
null_terminated_array_t(const string_list_t &argv) : array(NULL)
{
this->set(argv);
}
~null_terminated_array_t()
{
this->free();
}
/** operator=. Notice the pass-by-value parameter. */
null_terminated_array_t& operator=(null_terminated_array_t rhs) {
null_terminated_array_t& operator=(null_terminated_array_t rhs)
{
if (this != &rhs)
this->swap(rhs);
return *this;
}
/* Copy constructor. */
null_terminated_array_t(const null_terminated_array_t &him) : array(NULL) {
null_terminated_array_t(const null_terminated_array_t &him) : array(NULL)
{
this->set(him.array);
}
void set(const string_list_t &argv) {
void set(const string_list_t &argv)
{
/* Get rid of the old argv */
this->free();
/* Allocate our null-terminated array of null-terminated strings */
size_t i, count = argv.size();
this->array = new CharType_t * [count + 1];
for (i=0; i < count; i++) {
for (i=0; i < count; i++)
{
const string_t &str = argv.at(i);
this->array[i] = new CharType_t [1 + str.size()];
std::copy(str.begin(), str.end(), this->array[i]);
@ -405,19 +432,22 @@ class null_terminated_array_t {
}
this->array[count] = NULL;
}
void set(const CharType_t * const *new_array) {
void set(const CharType_t * const *new_array)
{
if (new_array == array)
return;
/* Get rid of the old argv */
this->free();
/* Copy the new one */
if (new_array) {
if (new_array)
{
size_t i, count = count_not_null(new_array);
this->array = new CharType_t * [count + 1];
for (i=0; i < count; i++) {
for (i=0; i < count; i++)
{
size_t len = count_not_null(new_array[i]);
this->array[i] = new CharType_t [1 + len];
std::copy(new_array[i], new_array[i] + len, this->array[i]);
@ -426,13 +456,21 @@ class null_terminated_array_t {
this->array[count] = NULL;
}
}
CharType_t **get() { return array; }
const CharType_t * const *get() const { return array; }
string_list_t to_list() const {
CharType_t **get()
{
return array;
}
const CharType_t * const *get() const
{
return array;
}
string_list_t to_list() const
{
string_list_t lst;
if (array != NULL) {
if (array != NULL)
{
size_t count = this->size();
lst.reserve(count);
lst.insert(lst.end(), array, array + count);
@ -445,27 +483,31 @@ class null_terminated_array_t {
null_terminated_array_t<char> convert_wide_array_to_narrow(const null_terminated_array_t<wchar_t> &arr);
/* Helper class to cache a narrow version of a wcstring in a malloc'd buffer, so that we can read it after fork() */
class narrow_string_rep_t {
private:
class narrow_string_rep_t
{
private:
const char *str;
/* No copying */
narrow_string_rep_t &operator=(const narrow_string_rep_t &);
narrow_string_rep_t(const narrow_string_rep_t &x);
public:
~narrow_string_rep_t() {
public:
~narrow_string_rep_t()
{
free((void *)str);
}
narrow_string_rep_t() : str(NULL) {}
void set(const wcstring &s) {
void set(const wcstring &s)
{
free((void *)str);
str = wcs2str(s.c_str());
}
const char *get() const {
const char *get() const
{
return str;
}
};
@ -473,10 +515,11 @@ class narrow_string_rep_t {
bool is_forked_child();
/* Basic scoped lock class */
class scoped_lock {
class scoped_lock
{
pthread_mutex_t *lock_obj;
bool locked;
/* No copying */
scoped_lock &operator=(const scoped_lock &);
scoped_lock(const scoped_lock &);
@ -489,21 +532,22 @@ public:
};
/* Wrapper around wcstok */
class wcstokenizer {
class wcstokenizer
{
wchar_t *buffer, *str, *state;
const wcstring sep;
/* No copying */
wcstokenizer &operator=(const wcstokenizer &);
wcstokenizer(const wcstokenizer &);
public:
wcstokenizer(const wcstring &s, const wcstring &separator);
bool next(wcstring &result);
~wcstokenizer();
};
/**
/**
Appends a path component, with a / if necessary
*/
void append_path_component(wcstring &path, const wcstring &component);
@ -516,38 +560,38 @@ void append_format(wcstring &str, const wchar_t *format, ...);
Returns a newly allocated wide character string array equivalent of
the specified multibyte character string array
*/
char **wcsv2strv( const wchar_t * const *in );
char **wcsv2strv(const wchar_t * const *in);
/**
Test if the given string is a valid variable name.
Test if the given string is a valid variable name.
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
wchar_t *wcsvarname( const wchar_t *str );
wchar_t *wcsvarname(const wchar_t *str);
/**
Test if the given string is a valid function name.
Test if the given string is a valid function name.
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
const wchar_t *wcsfuncname( const wchar_t *str );
const wchar_t *wcsfuncname(const wchar_t *str);
/**
Test if the given string is valid in a variable name
Test if the given string is valid in a variable name
\return 1 if this is a valid name, 0 otherwise
*/
int wcsvarchr( wchar_t chr );
int wcsvarchr(wchar_t chr);
/**
A wcswidth workalike. Fish uses this since the regular wcswidth seems flaky.
*/
int my_wcswidth( const wchar_t *c );
int my_wcswidth(const wchar_t *c);
/**
This functions returns the end of the quoted substring beginning at
@ -556,7 +600,7 @@ int my_wcswidth( const wchar_t *c );
\param in the position of the opening quote
*/
wchar_t *quote_end( const wchar_t *in );
wchar_t *quote_end(const wchar_t *in);
/**
A call to this function will reset the error counter. Some
@ -572,19 +616,19 @@ void error_reset();
This function behaves exactly like a wide character equivalent of
the C function setlocale, except that it will also try to detect if
the user is using a Unicode character set, and if so, use the
unicode ellipsis character as ellipsis, instead of '$'.
unicode ellipsis character as ellipsis, instead of '$'.
*/
wcstring wsetlocale( int category, const wchar_t *locale );
wcstring wsetlocale(int category, const wchar_t *locale);
/**
Checks if \c needle is included in the list of strings specified. A warning is printed if needle is zero.
\param needle the string to search for in the list
\param needle the string to search for in the list
\return zero if needle is not found, of if needle is null, non-zero otherwise
*/
__sentinel bool contains_internal( const wchar_t *needle, ... );
__sentinel bool contains_internal( const wcstring &needle, ... );
__sentinel bool contains_internal(const wchar_t *needle, ...);
__sentinel bool contains_internal(const wcstring &needle, ...);
/**
Call read while blocking the SIGCHLD signal. Should only be called
@ -614,9 +658,9 @@ ssize_t read_loop(int fd, void *buff, size_t count);
Because debug is often called to tell the user about an error,
before using wperror to give a specific error message, debug will
never ever modify the value of errno.
\param level the priority of the message. Lower number means higher priority. Messages with a priority_number higher than \c debug_level will be ignored..
\param msg the message format string.
\param msg the message format string.
Example:
@ -624,20 +668,20 @@ ssize_t read_loop(int fd, void *buff, size_t count);
will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that program_name is 'fish'.
*/
void debug( int level, const char *msg, ... );
void debug( int level, const wchar_t *msg, ... );
void debug(int level, const char *msg, ...);
void debug(int level, const wchar_t *msg, ...);
/**
Replace special characters with backslash escape sequences. Newline is
replaced with \n, etc.
replaced with \n, etc.
\param in The string to be escaped
\param escape_all Whether all characters wich hold special meaning in fish (Pipe, semicolon, etc,) should be escaped, or only unprintable characters
\return The escaped string, or 0 if there is not enough memory
*/
wchar_t *escape( const wchar_t *in, escape_flags_t flags );
wcstring escape_string( const wcstring &in, escape_flags_t flags );
wchar_t *escape(const wchar_t *in, escape_flags_t flags);
wcstring escape_string(const wcstring &in, escape_flags_t flags);
/**
Expand backslashed escapes and substitute them with their unescaped
@ -650,14 +694,14 @@ wcstring escape_string( const wcstring &in, escape_flags_t flags );
an invalid sequence is specified, 0 is returned.
*/
wchar_t *unescape( const wchar_t * in,
int escape_special );
wchar_t *unescape(const wchar_t * in,
int escape_special);
bool unescape_string( wcstring &str,
int escape_special );
bool unescape_string(wcstring &str,
int escape_special);
/**
/**
Returns the width of the terminal window, so that not all
functions that use these values continually have to keep track of
it separately.
@ -679,20 +723,20 @@ int common_get_height();
saving it in an internal variable used by common_get_wisth and
common_get_height().
*/
void common_handle_winch( int signal );
void common_handle_winch(int signal);
/**
Write paragraph of output to the specified stringbuffer, and redo
the linebreaks to fit the current screen.
*/
void write_screen( const wcstring &msg, wcstring &buff );
void write_screen(const wcstring &msg, wcstring &buff);
/**
Tokenize the specified string into the specified wcstring_list_t.
Tokenize the specified string into the specified wcstring_list_t.
\param val the input string. The contents of this string is not changed.
\param out the list in which to place the elements.
\param out the list in which to place the elements.
*/
void tokenize_variable_array( const wcstring &val, wcstring_list_t &out);
void tokenize_variable_array(const wcstring &val, wcstring_list_t &out);
/**
Make sure the specified direcotry exists. If needed, try to create
@ -700,7 +744,7 @@ void tokenize_variable_array( const wcstring &val, wcstring_list_t &out);
\return 0 if, at the time of function return the directory exists, -1 otherwise.
*/
int create_directory( const wcstring &d );
int create_directory(const wcstring &d);
/**
Print a short message about how to file a bug report to stderr
@ -740,7 +784,7 @@ void assert_is_not_forked_child(const char *who);
#define ASSERT_IS_NOT_FORKED_CHILD() ASSERT_IS_NOT_FORKED_CHILD_TRAMPOLINE(__FUNCTION__)
extern "C" {
__attribute__((noinline)) void debug_thread_error(void);
__attribute__((noinline)) void debug_thread_error(void);
}

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,8 @@
*/
#define PROG_COMPLETE_SEP L'\t'
enum {
enum
{
/**
Do not insert space afterwards if this is the only completion. (The
default is to try insert a space)
@ -109,32 +110,35 @@ class completion_t
private:
/* No public default constructor */
completion_t();
completion_t();
public:
/**
The completion string
*/
wcstring completion;
/**
The completion string
*/
wcstring completion;
/**
The description for this completion
*/
wcstring description;
/**
The description for this completion
*/
wcstring description;
/**
Flags determining the completion behaviour.
/**
Flags determining the completion behaviour.
Determines whether a space should be inserted after this
compeltion if it is the only possible completion using the
COMPLETE_NO_SPACE flag.
Determines whether a space should be inserted after this
compeltion if it is the only possible completion using the
COMPLETE_NO_SPACE flag.
The COMPLETE_NO_CASE can be used to signal that this completion
is case insensitive.
*/
int flags;
The COMPLETE_NO_CASE can be used to signal that this completion
is case insensitive.
*/
int flags;
bool is_case_insensitive() const { return !! (flags & COMPLETE_NO_CASE); }
bool is_case_insensitive() const
{
return !!(flags & COMPLETE_NO_CASE);
}
/* Construction. Note: defining these so that they are not inlined reduces the executable size. */
completion_t(const wcstring &comp, const wcstring &desc = L"", int flags_val = 0);
@ -142,21 +146,22 @@ public:
completion_t &operator=(const completion_t &);
/* 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
{
COMPLETE_DEFAULT,
COMPLETE_AUTOSUGGEST
};
/** Given a list of completions, returns a list of their completion fields */
wcstring_list_t completions_to_wcstring_list( const std::vector<completion_t> &completions );
wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &completions);
/** Sorts a list of completions */
void sort_completions( std::vector<completion_t> &completions);
void sort_completions(std::vector<completion_t> &completions);
/**
@ -203,30 +208,30 @@ void sort_completions( std::vector<completion_t> &completions);
If \c condition is empty, the completion is always used.
\param flags A set of completion flags
*/
void complete_add( const wchar_t *cmd,
bool cmd_is_path,
wchar_t short_opt,
const wchar_t *long_opt,
int long_mode,
int result_mode,
const wchar_t *condition,
const wchar_t *comp,
const wchar_t *desc,
int flags );
void complete_add(const wchar_t *cmd,
bool cmd_is_path,
wchar_t short_opt,
const wchar_t *long_opt,
int long_mode,
int result_mode,
const wchar_t *condition,
const wchar_t *comp,
const wchar_t *desc,
int flags);
/**
Sets whether the completion list for this command is complete. If
true, any options not matching one of the provided options will be
flagged as an error by syntax highlighting.
*/
void complete_set_authoritative( const wchar_t *cmd, bool cmd_type, bool authoritative );
void complete_set_authoritative(const wchar_t *cmd, bool cmd_type, bool authoritative);
/**
Remove a previously defined completion
*/
void complete_remove( const wchar_t *cmd,
bool cmd_is_path,
wchar_t short_opt,
const wchar_t *long_opt );
void complete_remove(const wchar_t *cmd,
bool cmd_is_path,
wchar_t short_opt,
const wchar_t *long_opt);
/** Find all completions of the command cmd, insert them into out. If to_load is
@ -243,23 +248,23 @@ void complete(const wcstring &cmd,
\param out The string to write completions to
*/
void complete_print( wcstring &out );
void complete_print(wcstring &out);
/**
Tests if the specified option is defined for the specified command
*/
int complete_is_valid_option( const wcstring &str,
const wcstring &opt,
wcstring_list_t *inErrorsOrNull,
bool allow_autoload );
int complete_is_valid_option(const wcstring &str,
const wcstring &opt,
wcstring_list_t *inErrorsOrNull,
bool allow_autoload);
/**
Tests if the specified argument is valid for the specified option
and command
*/
bool complete_is_valid_argument( const wcstring &str,
const wcstring &opt,
const wcstring &arg );
bool complete_is_valid_argument(const wcstring &str,
const wcstring &opt,
const wcstring &arg);
/**
@ -273,7 +278,7 @@ bool complete_is_valid_argument( const wcstring &str,
previously loaded. (This is set to true on actual completions, so that
changed completion are updated in running shells)
*/
void complete_load( const wcstring &cmd, bool reload );
void complete_load(const wcstring &cmd, bool reload);
/**
Create a new completion entry

1568
env.cpp

File diff suppressed because it is too large Load diff

41
env.h
View file

@ -46,9 +46,10 @@
/**
Error code for trying to alter read-only variable
*/
enum{
ENV_PERM = 1,
ENV_INVALID
enum
{
ENV_PERM = 1,
ENV_INVALID
}
;
@ -102,7 +103,8 @@ int env_set(const wcstring &key, const wchar_t *val, int mode);
*/
//const wchar_t *env_get( const wchar_t *key );
class env_var_t : public wcstring {
class env_var_t : public wcstring
{
private:
bool is_missing;
public:
@ -111,16 +113,24 @@ public:
env_var_t(const wcstring & x) : wcstring(x), is_missing(false) { }
env_var_t(const wchar_t *x) : wcstring(x), is_missing(false) { }
env_var_t() : wcstring(L""), is_missing(false) { }
bool missing(void) const { return is_missing; }
bool missing_or_empty(void) const { return missing() || empty(); }
bool missing(void) const
{
return is_missing;
}
bool missing_or_empty(void) const
{
return missing() || empty();
}
const wchar_t *c_str(void) const;
env_var_t &operator=(const env_var_t &s) {
env_var_t &operator=(const env_var_t &s)
{
is_missing = s.is_missing;
wcstring::operator=(s);
return *this;
}
bool operator==(const env_var_t &s) const {
bool operator==(const env_var_t &s) const
{
if (is_missing && s.is_missing)
return true;
else if (s.is_missing || s.is_missing)
@ -133,7 +143,7 @@ public:
/**
Gets the variable with the specified name, or an empty string if it does not exist.
*/
env_var_t env_get_string( const wcstring &key );
env_var_t env_get_string(const wcstring &key);
/**
Returns 1 if the specified key exists. This can't be reliably done
@ -142,7 +152,7 @@ env_var_t env_get_string( const wcstring &key );
\param key The name of the variable to remove
\param mode the scope to search in. All scopes are searched if unset
*/
int env_exist( const wchar_t *key, int mode );
int env_exist(const wchar_t *key, int mode);
/**
Remove environemnt variable
@ -152,12 +162,12 @@ int env_exist( const wchar_t *key, int mode );
\return zero if the variable existed, and non-zero if the variable did not exist
*/
int env_remove( const wcstring &key, int mode );
int env_remove(const wcstring &key, int mode);
/**
Push the variable stack. Used for implementing local variables for functions and for-loops.
*/
void env_push( int new_scope );
void env_push(int new_scope);
/**
Pop the variable stack. Used for implementing local variables for functions and for-loops.
@ -165,13 +175,13 @@ void env_push( int new_scope );
void env_pop();
/** Returns an array containing all exported variables in a format suitable for execv. */
char **env_export_arr( bool recalc );
char **env_export_arr(bool recalc);
void env_export_arr(bool recalc, null_terminated_array_t<char> &result);
/**
Returns all variable names.
*/
wcstring_list_t env_get_names( int flags );
wcstring_list_t env_get_names(int flags);
@ -181,7 +191,8 @@ wcstring_list_t env_get_names( int flags );
*/
int env_set_pwd();
class env_vars_snapshot_t {
class env_vars_snapshot_t
{
std::map<wcstring, wcstring> vars;
bool is_current() const;

View file

@ -61,7 +61,7 @@ static int get_socket_count = 0;
static wchar_t * path;
static wchar_t *user;
static void (*start_fishd)();
static void (*external_callback)( fish_message_type_t type, const wchar_t *name, const wchar_t *val );
static void (*external_callback)(fish_message_type_t type, const wchar_t *name, const wchar_t *val);
/**
Flag set to 1 when a barrier reply is recieved
@ -72,110 +72,110 @@ void env_universal_barrier();
static int is_dead()
{
return env_universal_server.fd < 0;
return env_universal_server.fd < 0;
}
/**
Get a socket for reading from the server
*/
static int get_socket( int fork_ok )
static int get_socket(int fork_ok)
{
int s, len;
struct sockaddr_un local;
int s, len;
struct sockaddr_un local;
char *name;
wchar_t *wdir;
wchar_t *wuname;
char *dir =0, *uname=0;
char *name;
wchar_t *wdir;
wchar_t *wuname;
char *dir =0, *uname=0;
get_socket_count++;
wdir = path;
wuname = user;
get_socket_count++;
wdir = path;
wuname = user;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
wperror(L"socket");
return -1;
}
if( wdir )
dir = wcs2str(wdir );
else
dir = strdup("/tmp");
if( wuname )
uname = wcs2str(wuname );
else
{
struct passwd *pw;
pw = getpwuid( getuid() );
uname = strdup( pw->pw_name );
}
name = (char *)malloc( strlen(dir) +
strlen(uname) +
strlen(SOCK_FILENAME) +
2 );
strcpy( name, dir );
strcat( name, "/" );
strcat( name, SOCK_FILENAME );
strcat( name, uname );
free( dir );
free( uname );
debug( 3, L"Connect to socket %s at fd %2", name, s );
local.sun_family = AF_UNIX;
strcpy(local.sun_path, name );
free( name );
len = sizeof(local);
if( connect( s, (struct sockaddr *)&local, len) == -1 )
{
close( s );
if( fork_ok && start_fishd )
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
debug( 2, L"Could not connect to socket %d, starting fishd", s );
start_fishd();
return get_socket( 0 );
wperror(L"socket");
return -1;
}
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;
}
if (wdir)
dir = wcs2str(wdir);
else
dir = strdup("/tmp");
if( (fcntl( s, F_SETFL, O_NONBLOCK ) != 0) || (fcntl( s, F_SETFD, FD_CLOEXEC ) != 0) )
{
wperror( L"fcntl" );
close( s );
if (wuname)
uname = wcs2str(wuname);
else
{
struct passwd *pw;
pw = getpwuid(getuid());
uname = strdup(pw->pw_name);
}
return -1;
}
name = (char *)malloc(strlen(dir) +
strlen(uname) +
strlen(SOCK_FILENAME) +
2);
debug( 3, L"Connected to fd %d", s );
strcpy(name, dir);
strcat(name, "/");
strcat(name, SOCK_FILENAME);
strcat(name, uname);
return s;
free(dir);
free(uname);
debug(3, L"Connect to socket %s at fd %2", name, s);
local.sun_family = AF_UNIX;
strcpy(local.sun_path, name);
free(name);
len = sizeof(local);
if (connect(s, (struct sockaddr *)&local, len) == -1)
{
close(s);
if (fork_ok && start_fishd)
{
debug(2, L"Could not connect to socket %d, starting fishd", s);
start_fishd();
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?");
return -1;
}
if ((fcntl(s, F_SETFL, O_NONBLOCK) != 0) || (fcntl(s, F_SETFD, FD_CLOEXEC) != 0))
{
wperror(L"fcntl");
close(s);
return -1;
}
debug(3, L"Connected to fd %d", s);
return s;
}
/**
Callback function used whenever a new fishd message is recieved
*/
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 )
{
barrier_reply = 1;
}
else
{
if( external_callback )
external_callback( type, name, val );
}
if (type == BARRIER_REPLY)
{
barrier_reply = 1;
}
else
{
if (external_callback)
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()
{
if( !init )
return;
if (!init)
return;
if( env_universal_server.killme )
{
debug( 3, L"Lost connection to universal variable server." );
if( close( env_universal_server.fd ) )
if (env_universal_server.killme)
{
wperror( L"close" );
}
debug(3, L"Lost connection to universal variable server.");
env_universal_server.fd = -1;
env_universal_server.killme=0;
env_universal_server.input.clear();
env_universal_read_all();
}
if (close(env_universal_server.fd))
{
wperror(L"close");
}
env_universal_server.fd = -1;
env_universal_server.killme=0;
env_universal_server.input.clear();
env_universal_read_all();
}
}
/**
@ -208,17 +208,17 @@ static void check_connection()
*/
static void env_universal_remove_all()
{
size_t i;
size_t i;
wcstring_list_t lst;
env_universal_common_get_names( lst,
1,
1 );
for( i=0; i<lst.size(); i++ )
{
const wcstring &key = lst.at(i);
env_universal_common_remove( key );
}
wcstring_list_t lst;
env_universal_common_get_names(lst,
1,
1);
for (i=0; i<lst.size(); i++)
{
const wcstring &key = lst.at(i);
env_universal_common_remove(key);
}
}
@ -230,63 +230,63 @@ static void env_universal_remove_all()
*/
static void reconnect()
{
if( get_socket_count >= RECONNECT_COUNT )
return;
if (get_socket_count >= RECONNECT_COUNT)
return;
debug( 3, L"Get new fishd connection" );
debug(3, L"Get new fishd connection");
init = 0;
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
env_universal_server.fd = get_socket(1);
init = 1;
if( env_universal_server.fd >= 0 )
{
env_universal_remove_all();
env_universal_barrier();
}
init = 0;
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
env_universal_server.fd = get_socket(1);
init = 1;
if (env_universal_server.fd >= 0)
{
env_universal_remove_all();
env_universal_barrier();
}
}
void env_universal_init( wchar_t * p,
wchar_t *u,
void (*sf)(),
void (*cb)( fish_message_type_t type, const wchar_t *name, const wchar_t *val ))
void env_universal_init(wchar_t * p,
wchar_t *u,
void (*sf)(),
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
{
path=p;
user=u;
start_fishd=sf;
external_callback = cb;
path=p;
user=u;
start_fishd=sf;
external_callback = cb;
connection_init( &env_universal_server, -1 );
connection_init(&env_universal_server, -1);
env_universal_server.fd = get_socket(1);
env_universal_common_init( &callback );
env_universal_read_all();
init = 1;
if( env_universal_server.fd >= 0 )
{
env_universal_barrier();
}
env_universal_server.fd = get_socket(1);
env_universal_common_init(&callback);
env_universal_read_all();
init = 1;
if (env_universal_server.fd >= 0)
{
env_universal_barrier();
}
}
void env_universal_destroy()
{
/*
Go into blocking mode and send all data before exiting
*/
if( env_universal_server.fd >= 0 )
{
if( fcntl( env_universal_server.fd, F_SETFL, 0 ) != 0 )
/*
Go into blocking mode and send all data before exiting
*/
if (env_universal_server.fd >= 0)
{
wperror( L"fcntl" );
if (fcntl(env_universal_server.fd, F_SETFL, 0) != 0)
{
wperror(L"fcntl");
}
try_send_all(&env_universal_server);
}
try_send_all( &env_universal_server );
}
connection_destroy( &env_universal_server );
env_universal_server.fd =-1;
env_universal_common_destroy();
init = 0;
connection_destroy(&env_universal_server);
env_universal_server.fd =-1;
env_universal_common_destroy();
init = 0;
}
@ -295,177 +295,177 @@ void env_universal_destroy()
*/
int env_universal_read_all()
{
if( !init)
return 0;
if (!init)
return 0;
if( env_universal_server.fd == -1 )
{
reconnect();
if( env_universal_server.fd == -1 )
return 0;
}
if (env_universal_server.fd == -1)
{
reconnect();
if (env_universal_server.fd == -1)
return 0;
}
if( env_universal_server.fd != -1 )
{
read_message( &env_universal_server );
check_connection();
return 1;
}
else
{
debug( 2, L"No connection to universal variable server" );
return 0;
}
if (env_universal_server.fd != -1)
{
read_message(&env_universal_server);
check_connection();
return 1;
}
else
{
debug(2, L"No connection to universal variable server");
return 0;
}
}
wchar_t *env_universal_get( const wcstring &name )
wchar_t *env_universal_get(const wcstring &name)
{
if( !init)
return 0;
if (!init)
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)
return 0;
if (!init)
return 0;
return env_universal_common_get_export( name );
return env_universal_common_get_export(name);
}
void env_universal_barrier()
{
ASSERT_IS_MAIN_THREAD();
message_t *msg;
fd_set fds;
message_t *msg;
fd_set fds;
if( !init || is_dead() )
return;
if (!init || is_dead())
return;
barrier_reply = 0;
barrier_reply = 0;
/*
Create barrier request
*/
msg= create_message( BARRIER, 0, 0);
msg->count=1;
/*
Create barrier request
*/
msg= create_message(BARRIER, 0, 0);
msg->count=1;
env_universal_server.unsent->push(msg);
/*
Wait until barrier request has been sent
*/
debug( 3, L"Create barrier" );
while( 1 )
{
try_send_all( &env_universal_server );
check_connection();
if( env_universal_server.unsent->empty() )
break;
if( env_universal_server.fd == -1 )
/*
Wait until barrier request has been sent
*/
debug(3, L"Create barrier");
while (1)
{
reconnect();
debug( 2, L"barrier interrupted, exiting" );
return;
try_send_all(&env_universal_server);
check_connection();
if (env_universal_server.unsent->empty())
break;
if (env_universal_server.fd == -1)
{
reconnect();
debug(2, L"barrier interrupted, exiting");
return;
}
FD_ZERO(&fds);
FD_SET(env_universal_server.fd, &fds);
select(env_universal_server.fd+1, 0, &fds, 0, 0);
}
FD_ZERO( &fds );
FD_SET( env_universal_server.fd, &fds );
select( env_universal_server.fd+1, 0, &fds, 0, 0 );
}
/*
Wait for barrier reply
*/
debug( 3, L"Sent barrier request" );
while( !barrier_reply )
{
if( env_universal_server.fd == -1 )
/*
Wait for barrier reply
*/
debug(3, L"Sent barrier request");
while (!barrier_reply)
{
reconnect();
debug( 2, L"barrier interrupted, exiting (2)" );
return;
if (env_universal_server.fd == -1)
{
reconnect();
debug(2, L"barrier interrupted, exiting (2)");
return;
}
FD_ZERO(&fds);
FD_SET(env_universal_server.fd, &fds);
select(env_universal_server.fd+1, &fds, 0, 0, 0);
env_universal_read_all();
}
FD_ZERO( &fds );
FD_SET( env_universal_server.fd, &fds );
select( env_universal_server.fd+1, &fds, 0, 0, 0 );
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 )
return;
if (!init)
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() )
{
env_universal_common_set( name.c_str(), value.c_str(), exportv );
}
else
{
msg = create_message( exportv?SET_EXPORT:SET,
name.c_str(),
value.c_str());
if( !msg )
if (is_dead())
{
debug( 1, L"Could not create universal variable message" );
return;
env_universal_common_set(name.c_str(), value.c_str(), exportv);
}
else
{
msg = create_message(exportv?SET_EXPORT:SET,
name.c_str(),
value.c_str());
if (!msg)
{
debug(1, L"Could not create universal variable message");
return;
}
msg->count=1;
env_universal_server.unsent->push(msg);
env_universal_barrier();
}
}
int env_universal_remove(const wchar_t *name)
{
int res;
message_t *msg;
if (!init)
return 1;
CHECK(name, 1);
res = !env_universal_common_get(name);
debug(3,
L"env_universal_remove( \"%ls\" )",
name);
if (is_dead())
{
env_universal_common_remove(wcstring(name));
}
else
{
msg= create_message(ERASE, name, 0);
msg->count=1;
env_universal_server.unsent->push(msg);
env_universal_barrier();
}
msg->count=1;
env_universal_server.unsent->push(msg);
env_universal_barrier();
}
return res;
}
int env_universal_remove( const wchar_t *name )
{
int res;
message_t *msg;
if( !init )
return 1;
CHECK( name, 1 );
res = !env_universal_common_get( name );
debug( 3,
L"env_universal_remove( \"%ls\" )",
name );
if( is_dead() )
{
env_universal_common_remove( wcstring(name) );
}
else
{
msg= create_message( ERASE, name, 0);
msg->count=1;
env_universal_server.unsent->push(msg);
env_universal_barrier();
}
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_unexported )
int show_unexported)
{
if( !init )
return;
if (!init)
return;
env_universal_common_get_names( lst,
show_exported,
show_unexported );
env_universal_common_get_names(lst,
show_exported,
show_unexported);
}

View file

@ -17,10 +17,10 @@ extern connection_t env_universal_server;
/**
Initialize the envuni library
*/
void env_universal_init( wchar_t * p,
void env_universal_init(wchar_t * p,
wchar_t *u,
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));
/**
Free memory used by envuni
*/
@ -29,24 +29,24 @@ void env_universal_destroy();
/**
Get the value of a universal variable
*/
wchar_t *env_universal_get( const wcstring &name );
wchar_t *env_universal_get(const wcstring &name);
/**
Get the export flag of the variable with the specified
name. Returns 0 if the variable doesn't exist.
*/
int env_universal_get_export( const wcstring &name );
int env_universal_get_export(const wcstring &name);
/**
Set the value of a universal variable
*/
void env_universal_set( const wcstring &name, const wcstring &val, int exportv );
void env_universal_set(const wcstring &name, const wcstring &val, int exportv);
/**
Erase a universal variable
\return zero if the variable existed, and non-zero if the variable did not exist
*/
int env_universal_remove( const wchar_t *name );
int env_universal_remove(const wchar_t *name);
/**
Read all available messages from the server.
@ -60,9 +60,9 @@ int env_universal_read_all();
\param show_exported whether exported variables should be shown
\param show_unexported whether unexported variables should be shown
*/
void env_universal_get_names2( wcstring_list_t &list,
int show_exported,
int show_unexported );
void env_universal_get_names2(wcstring_list_t &list,
int show_exported,
int show_unexported);
/**
Synchronize with fishd

File diff suppressed because it is too large Load diff

View file

@ -42,11 +42,11 @@
*/
typedef enum
{
SET,
SET_EXPORT,
ERASE,
BARRIER,
BARRIER_REPLY,
SET,
SET_EXPORT,
ERASE,
BARRIER,
BARRIER_REPLY,
} fish_message_type_t;
/**
@ -59,15 +59,15 @@ typedef enum
*/
typedef struct
{
/**
Number of queues that contain this message. Once this reaches zero, the message should be deleted
*/
int count;
/**
Number of queues that contain this message. Once this reaches zero, the message should be deleted
*/
int count;
/**
Message body. The message must be allocated using enough memory to actually contain the message.
*/
std::string body;
/**
Message body. The message must be allocated using enough memory to actually contain the message.
*/
std::string body;
} message_t;
@ -78,66 +78,66 @@ typedef std::queue<message_t *> message_queue_t;
*/
typedef struct connection
{
/**
The file descriptor this socket lives on
*/
int fd;
/**
Queue of onsent messages
*/
/**
The file descriptor this socket lives on
*/
int fd;
/**
Queue of onsent messages
*/
message_queue_t *unsent;
/**
Set to one when this connection should be killed
*/
int killme;
/**
The input string. Input from the socket goes here. When a
newline is encountered, the buffer is parsed and cleared.
*/
std::vector<char> input;
/**
Set to one when this connection should be killed
*/
int killme;
/**
The input string. Input from the socket goes here. When a
newline is encountered, the buffer is parsed and cleared.
*/
std::vector<char> input;
/**
The read buffer.
*/
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
/**
The read buffer.
*/
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
/**
Number of bytes that have already been consumed.
*/
size_t buffer_consumed;
/**
Number of bytes that have already been consumed.
*/
size_t buffer_consumed;
/**
Number of bytes that have been read into the buffer.
*/
size_t buffer_used;
/**
Number of bytes that have been read into the buffer.
*/
size_t buffer_used;
/**
Link to the next connection
*/
struct connection *next;
/**
Link to the next connection
*/
struct connection *next;
}
connection_t;
connection_t;
/**
Read all available messages on this connection
*/
void read_message( connection_t * );
void read_message(connection_t *);
/**
Send as many messages as possible without blocking to the connection
*/
void try_send_all( connection_t *c );
void try_send_all(connection_t *c);
/**
Create a messge with the specified properties
*/
message_t *create_message( fish_message_type_t type, const wchar_t *key, const wchar_t *val );
message_t *create_message(fish_message_type_t type, const wchar_t *key, const wchar_t *val);
/**
Init the library
*/
void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val ) );
void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val));
/**
Destroy library data
@ -150,9 +150,9 @@ void env_universal_common_destroy();
This function operate agains the local copy of all universal
variables, it does not communicate with any other process.
*/
void env_universal_common_get_names( wcstring_list_t &lst,
int show_exported,
int show_unexported );
void env_universal_common_get_names(wcstring_list_t &lst,
int show_exported,
int show_unexported);
/**
Perform the specified variable assignment.
@ -163,7 +163,7 @@ void env_universal_common_get_names( wcstring_list_t &lst,
Do not call this function. Create a message to do it. This function
is only to be used when fishd is dead.
*/
void env_universal_common_set( const wchar_t *key, const wchar_t *val, int exportv );
void env_universal_common_set(const wchar_t *key, const wchar_t *val, int exportv);
/**
Remove the specified variable.
@ -174,7 +174,7 @@ void env_universal_common_set( const wchar_t *key, const wchar_t *val, int expor
Do not call this function. Create a message to do it. This function
is only to be used when fishd is dead.
*/
void env_universal_common_remove( const wcstring &key );
void env_universal_common_remove(const wcstring &key);
/**
Get the value of the variable with the specified name
@ -182,7 +182,7 @@ void env_universal_common_remove( const wcstring &key );
This function operate agains the local copy of all universal
variables, it does not communicate with any other process.
*/
wchar_t *env_universal_common_get( const wcstring &name );
wchar_t *env_universal_common_get(const wcstring &name);
/**
Get the export flag of the variable with the specified
@ -191,24 +191,24 @@ wchar_t *env_universal_common_get( const wcstring &name );
This function operate agains the local copy of all universal
variables, it does not communicate with any other process.
*/
int env_universal_common_get_export( const wcstring &name );
int env_universal_common_get_export(const wcstring &name);
/**
Add messages about all existing variables to the specified connection
*/
void enqueue_all( connection_t *c );
void enqueue_all(connection_t *c);
/**
Fill in the specified connection_t struct. Use the specified file
descriptor for communication.
*/
void connection_init( connection_t *c, int fd );
void connection_init(connection_t *c, int fd);
/**
Close and destroy the specified connection struct. This frees
allstructures allocated by the connection, such as ques of unsent
messages.
*/
void connection_destroy( connection_t *c);
void connection_destroy(connection_t *c);
#endif

615
event.cpp
View file

@ -36,27 +36,27 @@
*/
typedef struct
{
/**
Number of delivered signals
*/
int count;
/**
Whether signals have been skipped
*/
int overflow;
/**
Array of signal events
*/
int signal[SIG_UNHANDLED_MAX];
/**
Number of delivered signals
*/
int count;
/**
Whether signals have been skipped
*/
int overflow;
/**
Array of signal events
*/
int signal[SIG_UNHANDLED_MAX];
}
signal_list_t;
signal_list_t;
/**
The signal event list. Actually two separate lists. One which is
active, which is the one that new events is written to. The inactive
one contains the events that are currently beeing performed.
*/
static signal_list_t sig_list[]={{0,0},{0,0}};
static signal_list_t sig_list[]= {{0,0},{0,0}};
/**
The index of sig_list that is the list of signals currently written to
@ -86,52 +86,52 @@ static event_list_t blocked;
they must name the same function.
*/
static int event_match( const event_t *classv, const event_t *instance )
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( ! classv->function_name.empty() &&
! instance->function_name.empty() &&
classv->function_name != instance->function_name)
{
if (! classv->function_name.empty() &&
! instance->function_name.empty() &&
classv->function_name != instance->function_name)
{
return 0;
}
}
if( classv->type == EVENT_ANY )
return 1;
if (classv->type == EVENT_ANY)
return 1;
if( classv->type != instance->type )
return 0;
if (classv->type != instance->type)
return 0;
switch( classv->type )
{
switch (classv->type)
{
case EVENT_SIGNAL:
if( classv->param1.signal == EVENT_ANY_SIGNAL )
return 1;
return classv->param1.signal == instance->param1.signal;
if (classv->param1.signal == EVENT_ANY_SIGNAL)
return 1;
return classv->param1.signal == instance->param1.signal;
case EVENT_VARIABLE:
return instance->str_param1 == classv->str_param1;
return instance->str_param1 == classv->str_param1;
case EVENT_EXIT:
if( classv->param1.pid == EVENT_ANY_PID )
return 1;
return classv->param1.pid == instance->param1.pid;
if (classv->param1.pid == EVENT_ANY_PID)
return 1;
return classv->param1.pid == instance->param1.pid;
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:
return instance->str_param1 == classv->str_param1;
return instance->str_param1 == classv->str_param1;
}
}
/**
This should never be reached
*/
return 0;
/**
This should never be reached
*/
return 0;
}
@ -139,95 +139,97 @@ static int event_match( const event_t *classv, const event_t *instance )
Create an identical copy of an event. Use deep copying, i.e. make
duplicates of any strings used as well.
*/
static event_t *event_copy( const event_t *event, int copy_arguments )
static event_t *event_copy(const event_t *event, int copy_arguments)
{
event_t *e = new event_t(*event);
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);
}
}
return e;
return e;
}
/**
Test if specified event is blocked
*/
static int event_is_blocked( event_t *e )
static int event_is_blocked(event_t *e)
{
block_t *block;
parser_t &parser = parser_t::principal_parser();
for( block = parser.current_block; block; block = block->outer )
{
block_t *block;
parser_t &parser = parser_t::principal_parser();
for (block = parser.current_block; block; block = block->outer)
{
if (event_block_list_blocks_type(block->event_blocks, e->type))
return true;
}
}
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;
switch( e->type )
{
wcstring result;
switch (e->type)
{
case EVENT_SIGNAL:
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal ), signal_get_desc( e->param1.signal ));
break;
result = format_string(_(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal), signal_get_desc(e->param1.signal));
break;
case EVENT_VARIABLE:
result = format_string(_(L"handler for variable '%ls'"), e->str_param1.c_str() );
break;
result = format_string(_(L"handler for variable '%ls'"), e->str_param1.c_str());
break;
case EVENT_EXIT:
if( e->param1.pid > 0 )
{
result = format_string(_(L"exit handler for process %d"), e->param1.pid );
}
else
{
job_t *j = job_get_from_pid( -e->param1.pid );
if( j )
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
if (e->param1.pid > 0)
{
result = format_string(_(L"exit handler for process %d"), e->param1.pid);
}
else
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid );
}
{
job_t *j = job_get_from_pid(-e->param1.pid);
if (j)
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
else
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid);
}
break;
break;
case EVENT_JOB_ID:
{
job_t *j = job_get( e->param1.job_id );
if( j )
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
else
result = format_string(_(L"exit handler for job with job id %d"), e->param1.job_id );
job_t *j = job_get(e->param1.job_id);
if (j)
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr());
else
result = format_string(_(L"exit handler for job with job id %d"), e->param1.job_id);
break;
break;
}
case EVENT_GENERIC:
result = format_string(_(L"handler for generic event '%ls'"), e->str_param1.c_str() );
break;
result = format_string(_(L"handler for generic event '%ls'"), e->str_param1.c_str());
break;
default:
result = format_string(_(L"Unknown event type") );
break;
result = format_string(_(L"Unknown event type"));
break;
}
}
return result;
return result;
}
#if 0
static void show_all_handlers(void) {
static void show_all_handlers(void)
{
puts("event handlers:");
for (event_list_t::const_iterator iter = events.begin(); iter != events.end(); ++iter) {
for (event_list_t::const_iterator iter = events.begin(); iter != events.end(); ++iter)
{
const event_t *foo = *iter;
wcstring tmp = event_get_desc(foo);
printf(" handler now %ls\n", tmp.c_str());
@ -235,18 +237,18 @@ static void show_all_handlers(void) {
}
#endif
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 )
{
signal_handle( e->param1.signal, 1 );
}
if (e->type == EVENT_SIGNAL)
{
signal_handle(e->param1.signal, 1);
}
// Block around updating the events vector
signal_block();
@ -254,78 +256,78 @@ void event_add_handler( const event_t *event )
signal_unblock();
}
void event_remove( event_t *criterion )
void event_remove(event_t *criterion)
{
size_t i;
event_list_t new_list;
size_t i;
event_list_t new_list;
CHECK( criterion, );
CHECK(criterion,);
/*
Because of concurrency issues (env_remove could remove an event
that is currently being executed), env_remove does not actually
free any events - instead it simply moves all events that should
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
events-list.
*/
/*
Because of concurrency issues (env_remove could remove an event
that is currently being executed), env_remove does not actually
free any events - instead it simply moves all events that should
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
events-list.
*/
if( events.empty() )
return;
if (events.empty())
return;
for( i=0; i<events.size(); i++ )
{
event_t *n = events.at(i);
if( event_match( criterion, n ) )
for (i=0; i<events.size(); i++)
{
event_t *n = events.at(i);
if (event_match(criterion, n))
{
killme.push_back(n);
/*
If this event was a signal handler and no other handler handles
the specified signal type, do not handle that type of signal any
more.
*/
if( n->type == EVENT_SIGNAL )
{
/*
If this event was a signal handler and no other handler handles
the specified signal type, do not handle that type of signal any
more.
*/
if (n->type == EVENT_SIGNAL)
{
event_t e = event_t::signal_event(n->param1.signal);
if( event_get( &e, 0 ) == 1 )
{
signal_handle( e.param1.signal, 0 );
if (event_get(&e, 0) == 1)
{
signal_handle(e.param1.signal, 0);
}
}
}
}
}
else
{
else
{
new_list.push_back(n);
}
}
}
signal_block();
events.swap(new_list);
events.swap(new_list);
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;
int found = 0;
size_t i;
int found = 0;
if( events.empty() )
return 0;
if (events.empty())
return 0;
CHECK( criterion, 0 );
CHECK(criterion, 0);
for( i=0; i<events.size(); i++ )
{
event_t *n = events.at(i);
if( event_match(criterion, n ) )
for (i=0; i<events.size(); i++)
{
found++;
if( out )
event_t *n = events.at(i);
if (event_match(criterion, n))
{
found++;
if (out)
out->push_back(n);
}
}
}
return found;
return found;
}
bool event_is_signal_observed(int sig)
@ -343,7 +345,7 @@ bool event_is_signal_observed(int sig)
}
else if (event->type == EVENT_SIGNAL)
{
if( event->param1.signal == EVENT_ANY_SIGNAL || event->param1.signal == sig)
if (event->param1.signal == EVENT_ANY_SIGNAL || event->param1.signal == sig)
return true;
}
}
@ -362,7 +364,7 @@ static void event_free_kills()
/**
Test if the specified event is waiting to be killed
*/
static int event_is_killed( event_t *e )
static int event_is_killed(event_t *e)
{
return std::find(killme.begin(), killme.end(), e) != killme.end();
}
@ -373,71 +375,71 @@ static int event_is_killed( event_t *e )
optimize the 'no matches' path. This means that nothing is
allocated/initialized unless needed.
*/
static void event_fire_internal( const event_t *event )
static void event_fire_internal(const event_t *event)
{
size_t i, j;
event_list_t fire;
/*
First we free all events that have been removed
*/
event_free_kills();
if( events.empty() )
return;
/*
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
since an event handler might call event_remove or
event_add_handler, which will change the contents of the \c
events list.
*/
for( i=0; i<events.size(); i++ )
{
event_t *criterion = events.at(i);
size_t i, j;
event_list_t fire;
/*
Check if this event is a match
First we free all events that have been removed
*/
if(event_match( criterion, event ) )
event_free_kills();
if (events.empty())
return;
/*
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
since an event handler might call event_remove or
event_add_handler, which will change the contents of the \c
events list.
*/
for (i=0; i<events.size(); i++)
{
event_t *criterion = events.at(i);
/*
Check if this event is a match
*/
if (event_match(criterion, event))
{
fire.push_back(criterion);
}
}
}
/*
No matches. Time to return.
*/
if( fire.empty() )
return;
/*
Iterate over our list of matching events
*/
for( i=0; i<fire.size(); i++ )
{
event_t *criterion = fire.at(i);
int prev_status;
/*
Check if this event has been removed, if so, dont fire it
No matches. Time to return.
*/
if( event_is_killed( criterion ) )
continue;
if (fire.empty())
return;
/*
Fire event
Iterate over our list of matching events
*/
wcstring buffer = criterion->function_name;
for (i=0; i<fire.size(); i++)
{
event_t *criterion = fire.at(i);
int prev_status;
/*
Check if this event has been removed, if so, dont fire it
*/
if (event_is_killed(criterion))
continue;
/*
Fire event
*/
wcstring buffer = criterion->function_name;
if (event->arguments.get())
{
for( j=0; j< event->arguments->size(); j++ )
for (j=0; j< event->arguments->size(); j++)
{
wcstring arg_esc = escape_string( event->arguments->at(j), 1 );
wcstring arg_esc = escape_string(event->arguments->at(j), 1);
buffer += L" ";
buffer += arg_esc;
}
@ -445,26 +447,26 @@ static void event_fire_internal( const event_t *event )
// debug( 1, L"Event handler fires command '%ls'", buffer.c_str() );
/*
Event handlers are not part of the main flow of code, so
they are marked as non-interactive
*/
proc_push_interactive(0);
prev_status = proc_get_last_status();
/*
Event handlers are not part of the main flow of code, so
they are marked as non-interactive
*/
proc_push_interactive(0);
prev_status = proc_get_last_status();
parser_t &parser = parser_t::principal_parser();
block_t *block = new event_block_t(event);
parser.push_block(block);
parser.eval( buffer, io_chain_t(), TOP );
parser.pop_block();
proc_pop_interactive();
proc_set_last_status( prev_status );
}
parser.push_block(block);
parser.eval(buffer, io_chain_t(), TOP);
parser.pop_block();
proc_pop_interactive();
proc_set_last_status(prev_status);
}
/*
Free killed events
*/
event_free_kills();
/*
Free killed events
*/
event_free_kills();
}
@ -474,78 +476,78 @@ static void event_fire_internal( const event_t *event )
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
another event, we do not want to fire delayed events because of
concurrency problems.
*/
if( ! blocked.empty() && is_event==1)
{
event_list_t new_blocked;
for( i=0; i<blocked.size(); i++ )
When the event handler has called a piece of code that triggers
another event, we do not want to fire delayed events because of
concurrency problems.
*/
if (! blocked.empty() && is_event==1)
{
event_t *e = blocked.at(i);
if( event_is_blocked( e ) )
{
event_list_t new_blocked;
for (i=0; i<blocked.size(); i++)
{
event_t *e = blocked.at(i);
if (event_is_blocked(e))
{
new_blocked.push_back(e);
}
else
{
event_fire_internal( e );
event_free( e );
}
}
}
else
{
event_fire_internal(e);
event_free(e);
}
}
blocked.swap(new_blocked);
}
}
while( sig_list[active_list].count > 0 )
{
signal_list_t *lst;
while (sig_list[active_list].count > 0)
{
signal_list_t *lst;
/*
Switch signal lists
*/
sig_list[1-active_list].count=0;
sig_list[1-active_list].overflow=0;
active_list=1-active_list;
/*
Switch signal lists
*/
sig_list[1-active_list].count=0;
sig_list[1-active_list].overflow=0;
active_list=1-active_list;
/*
Set up
*/
/*
Set up
*/
event_t e = event_t::signal_event(0);
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 )
{
debug( 0, _( L"Signal list overflow. Signals have been ignored." ) );
}
if (lst->overflow)
{
debug(0, _(L"Signal list overflow. Signals have been ignored."));
}
/*
Send all signals in our private list
*/
for( int i=0; i < lst->count; i++ )
{
e.param1.signal = lst->signal[i];
e.arguments->at(0) = sig2wcs( e.param1.signal );
if( event_is_blocked( &e ) )
{
/*
Send all signals in our private list
*/
for (int i=0; i < lst->count; i++)
{
e.param1.signal = lst->signal[i];
e.arguments->at(0) = sig2wcs(e.param1.signal);
if (event_is_blocked(&e))
{
blocked.push_back(event_copy(&e, 1));
}
else
{
event_fire_internal( &e );
}
}
}
else
{
event_fire_internal(&e);
}
}
e.arguments.reset(NULL);
}
}
}
void event_fire_signal(int signal)
@ -556,42 +558,42 @@ void event_fire_signal(int signal)
allocation or something else that might be bad when in a
signal handler.
*/
if( sig_list[active_list].count < SIG_UNHANDLED_MAX )
if (sig_list[active_list].count < SIG_UNHANDLED_MAX)
sig_list[active_list].signal[sig_list[active_list].count++]=signal;
else
sig_list[active_list].overflow=1;
}
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);
}
else
{
}
else
{
is_event++;
/*
Fire events triggered by signals
*/
event_fire_delayed();
/*
Fire events triggered by signals
*/
event_fire_delayed();
if( event )
{
if( event_is_blocked( event ) )
{
if (event)
{
if (event_is_blocked(event))
{
blocked.push_back(event_copy(event, 1));
}
else
{
event_fire_internal( event );
}
}
}
else
{
event_fire_internal(event);
}
}
is_event--;
}
}
}
@ -609,57 +611,60 @@ void event_destroy()
killme.clear();
}
void event_free( event_t *e )
void event_free(event_t *e)
{
CHECK( e, );
CHECK(e,);
delete e;
}
void event_fire_generic_internal(const wchar_t *name, ...)
{
va_list va;
wchar_t *arg;
va_list va;
wchar_t *arg;
CHECK( name, );
CHECK(name,);
event_t ev(EVENT_GENERIC);
ev.str_param1 = name;
event_t ev(EVENT_GENERIC);
ev.str_param1 = name;
ev.arguments.reset(new wcstring_list_t);
va_start( va, name );
while( (arg=va_arg(va, wchar_t *) )!= 0 )
{
va_start(va, name);
while ((arg=va_arg(va, wchar_t *))!= 0)
{
ev.arguments->push_back(arg);
}
va_end( va );
}
va_end(va);
event_fire( &ev );
event_fire(&ev);
ev.arguments.reset(NULL);
}
event_t event_t::signal_event(int sig) {
event_t event_t::signal_event(int sig)
{
event_t event(EVENT_SIGNAL);
event.param1.signal = sig;
return event;
}
event_t event_t::variable_event(const wcstring &str) {
event_t event_t::variable_event(const wcstring &str)
{
event_t event(EVENT_VARIABLE);
event.str_param1 = str;
return event;
}
event_t event_t::generic_event(const wcstring &str) {
event_t event_t::generic_event(const wcstring &str)
{
event_t event(EVENT_GENERIC);
event.str_param1 = str;
return event;
}
event_t::event_t(const event_t &x) :
type(x.type),
param1(x.param1),
str_param1(x.str_param1),
function_name(x.function_name)
type(x.type),
param1(x.param1),
str_param1(x.str_param1),
function_name(x.function_name)
{
const wcstring_list_t *ptr = x.arguments.get();
if (ptr)

67
event.h
View file

@ -31,14 +31,14 @@
*/
enum
{
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_VARIABLE, /**< An event triggered by a variable update */
EVENT_EXIT, /**< An event triggered by a job or process exit */
EVENT_JOB_ID, /**< An event triggered by a job exit */
EVENT_GENERIC, /**< A generic event */
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_VARIABLE, /**< An event triggered by a variable update */
EVENT_EXIT, /**< An event triggered by a job or process exit */
EVENT_JOB_ID, /**< An event triggered by a job exit */
EVENT_GENERIC, /**< A generic event */
}
;
;
/**
The structure which represents an event. The event_t struct has
@ -49,18 +49,19 @@ enum
*/
struct event_t
{
/**
Type of event
*/
int type;
/** 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
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
/**
Type of event
*/
union {
int type;
/** 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
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
*/
union
{
int signal;
int job_id;
pid_t pid;
@ -73,16 +74,16 @@ struct event_t
*/
wcstring str_param1;
/**
The name of the event handler function
*/
wcstring function_name;
/**
The name of the event handler function
*/
wcstring function_name;
/**
The argument list. Only used when sending a new event using
event_fire. In all other situations, the value of this variable
is ignored.
*/
/**
The argument list. Only used when sending a new event using
event_fire. In all other situations, the value of this variable
is ignored.
*/
std::auto_ptr<wcstring_list_t> arguments;
event_t(int t) : type(t), param1(), str_param1(), function_name(), arguments() { }
@ -100,14 +101,14 @@ struct event_t
May not be called by a signal handler, since it may allocate new memory.
*/
void event_add_handler( const event_t *event );
void event_add_handler(const event_t *event);
/**
Remove all events matching the specified criterion.
May not be called by a signal handler, since it may free allocated memory.
*/
void event_remove( event_t *event );
void event_remove(event_t *event);
/**
Return all events which match the specified event class
@ -120,7 +121,7 @@ void event_remove( event_t *event );
\return the number of found matches
*/
int event_get( event_t *criterion, std::vector<event_t *> *out );
int event_get(event_t *criterion, std::vector<event_t *> *out);
/**
Returns whether an event listener is registered for the given signal.
@ -144,7 +145,7 @@ bool event_is_signal_observed(int signal);
\param event the specific event whose handlers should fire. If
null, then all delayed events will be fired.
*/
void event_fire( event_t *event );
void event_fire(event_t *event);
/** Like event_fire, but takes a signal directly. */
void event_fire_signal(int signal);
@ -162,12 +163,12 @@ void event_destroy();
/**
Free all memory used by the specified event
*/
void event_free( event_t *e );
void event_free(event_t *e);
/**
Returns a string describing the specified event.
*/
wcstring event_get_desc( const event_t *e );
wcstring event_get_desc(const event_t *e);
/**
Fire a generic event with the specified name

2025
exec.cpp

File diff suppressed because it is too large Load diff

14
exec.h
View file

@ -42,7 +42,7 @@
*/
class parser_t;
void exec( parser_t &parser, job_t *j );
void exec(parser_t &parser, job_t *j);
/**
Evaluate the expression cmd in a subshell, add the outputs into the
@ -54,29 +54,29 @@ void exec( parser_t &parser, job_t *j );
\return the status of the last job to exit, or -1 if en error was encountered.
*/
__warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs );
__warn_unused int exec_subshell(const wcstring &cmd );
__warn_unused int exec_subshell(const wcstring &cmd, std::vector<wcstring> &outputs);
__warn_unused int exec_subshell(const wcstring &cmd);
/**
Loops over close until the syscall was run without being
interrupted. Then removes the fd from the open_fds list.
*/
void exec_close( int fd );
void exec_close(int fd);
/**
Call pipe(), and add resulting fds to open_fds, the list of opend
file descriptors for pipes.
*/
int exec_pipe( int fd[2]);
int exec_pipe(int fd[2]);
/* Close all fds in open_fds. This is called from postfork.cpp */
void close_unused_internal_pipes( const io_chain_t &io );
void close_unused_internal_pipes(const io_chain_t &io);
/* Gets all unused internal pipes into fds */
void get_unused_internal_pipes(std::vector<int> &fds, const io_chain_t &io);
/** Gets the interpreter for a given command */
char *get_interpreter( const char *command, char *interpreter, size_t buff_size );
char *get_interpreter(const char *command, char *interpreter, size_t buff_size);
#endif

1510
expand.cpp

File diff suppressed because it is too large Load diff

View file

@ -21,7 +21,8 @@
#include "common.h"
#include <list>
enum {
enum
{
/** Flag specifying that cmdsubst expansion should be skipped */
EXPAND_SKIP_CMDSUBST = 1 << 0,
@ -69,33 +70,33 @@ class completion_t;
enum
{
/** Character represeting a home directory */
HOME_DIRECTORY = EXPAND_RESERVED,
/** Character represeting a home directory */
HOME_DIRECTORY = EXPAND_RESERVED,
/** Character represeting process expansion */
PROCESS_EXPAND,
/** Character represeting process expansion */
PROCESS_EXPAND,
/** Character representing variable expansion */
VARIABLE_EXPAND,
/** Character representing variable expansion */
VARIABLE_EXPAND,
/** Character rpresenting variable expansion into a single element*/
VARIABLE_EXPAND_SINGLE,
/** Character rpresenting variable expansion into a single element*/
VARIABLE_EXPAND_SINGLE,
/** Character representing the start of a bracket expansion */
BRACKET_BEGIN,
/** Character representing the start of a bracket expansion */
BRACKET_BEGIN,
/** Character representing the end of a bracket expansion */
BRACKET_END,
/** Character representing the end of a bracket expansion */
BRACKET_END,
/** Character representing separation between two bracket elements */
BRACKET_SEP,
/**
Separate subtokens in a token with this character.
*/
INTERNAL_SEPARATOR,
/** Character representing separation between two bracket elements */
BRACKET_SEP,
/**
Separate subtokens in a token with this character.
*/
INTERNAL_SEPARATOR,
}
;
;
/**
@ -103,14 +104,14 @@ enum
*/
enum
{
/** Error */
EXPAND_ERROR,
/** Ok */
EXPAND_OK,
/** Ok, a wildcard in the string matched no files */
EXPAND_WILDCARD_NO_MATCH,
/* Ok, a wildcard in the string matched a file */
EXPAND_WILDCARD_MATCH
/** Error */
EXPAND_ERROR,
/** Ok */
EXPAND_OK,
/** Ok, a wildcard in the string matched no files */
EXPAND_WILDCARD_NO_MATCH,
/* Ok, a wildcard in the string matched a file */
EXPAND_WILDCARD_MATCH
};
/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
@ -141,7 +142,7 @@ class parser_t;
\param flag Specifies if any expansion pass should be skipped. Legal values are any combination of EXPAND_SKIP_CMDSUBST EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH. EXPAND_WILDCARD_NO_MATCH and EXPAND_WILDCARD_MATCH are normal exit conditions used only on strings containing wildcards to tell if the wildcard produced any matches.
*/
__warn_unused int expand_string( const wcstring &input, std::vector<completion_t> &output, expand_flags_t flags );
__warn_unused int expand_string(const wcstring &input, std::vector<completion_t> &output, expand_flags_t flags);
/**
@ -153,14 +154,14 @@ __warn_unused int expand_string( const wcstring &input, std::vector<completion_t
\param flag Specifies if any expansion pass should be skipped. Legal values are any combination of EXPAND_SKIP_CMDSUBST EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\return Whether expansion succeded
*/
bool expand_one( wcstring &inout_str, expand_flags_t flags );
bool expand_one(wcstring &inout_str, expand_flags_t flags);
/**
Convert the variable value to a human readable form, i.e. escape things, handle arrays, etc. Suitable for pretty-printing. The result must be free'd!
\param in the value to escape
*/
wcstring expand_escape_variable( const wcstring &in );
wcstring expand_escape_variable(const wcstring &in);
/**
Perform tilde expansion and nothing else on the specified string, which is modified in place.
@ -180,7 +181,7 @@ void expand_tilde(wcstring &input);
\param in the string to test
*/
int expand_is_clean( const wchar_t *in );
int expand_is_clean(const wchar_t *in);
/**
Perform error reporting for a syntax error related to the variable
@ -192,7 +193,7 @@ int expand_is_clean( const wchar_t *in );
\param token_pos The position where the expansion begins
\param error_pos The position on the line to report to the error function.
*/
void expand_variable_error( parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos );
void expand_variable_error(parser_t &parser, const wchar_t *token, size_t token_pos, int error_pos);
/**
Testing function for getting all process names.

File diff suppressed because it is too large Load diff

View file

@ -63,14 +63,14 @@ typedef char tputs_arg_t;
*/
struct winsize
{
/**
Number of rows
*/
unsigned short ws_row;
/**
Number of columns
*/
unsigned short ws_col;
/**
Number of rows
*/
unsigned short ws_row;
/**
Number of columns
*/
unsigned short ws_col;
}
;
@ -94,7 +94,7 @@ int tputs(const char *str, int affcnt, int (*fish_putc)(tputs_arg_t));
*/
#define tparm tparm_solaris_kludge
char *tparm_solaris_kludge( char *str, ... );
char *tparm_solaris_kludge(char *str, ...);
#endif
@ -107,7 +107,7 @@ char *tparm_solaris_kludge( char *str, ... );
strings and decimal numbers, position (%n), field width and
precision.
*/
int fwprintf( FILE *f, const wchar_t *format, ... );
int fwprintf(FILE *f, const wchar_t *format, ...);
/**
@ -117,7 +117,7 @@ int fwprintf( FILE *f, const wchar_t *format, ... );
strings and decimal numbers, position (%n), field width and
precision.
*/
int swprintf( wchar_t *str, size_t l, const wchar_t *format, ... );
int swprintf(wchar_t *str, size_t l, const wchar_t *format, ...);
/**
Print formated string. Some operating systems (Like NetBSD) do not
@ -126,7 +126,7 @@ int swprintf( wchar_t *str, size_t l, const wchar_t *format, ... );
strings and decimal numbers, position (%n), field width and
precision.
*/
int wprintf( const wchar_t *format, ... );
int wprintf(const wchar_t *format, ...);
/**
Print formated string. Some operating systems (Like NetBSD) do not
@ -135,7 +135,7 @@ int wprintf( const wchar_t *format, ... );
strings and decimal numbers, position (%n), field width and
precision.
*/
int vwprintf( const wchar_t *filter, va_list va );
int vwprintf(const wchar_t *filter, va_list va);
/**
Print formated string. Some operating systems (Like NetBSD) do not
@ -144,7 +144,7 @@ int vwprintf( const wchar_t *filter, va_list va );
strings and decimal numbers, position (%n), field width and
precision.
*/
int vfwprintf( FILE *f, const wchar_t *filter, va_list va );
int vfwprintf(FILE *f, const wchar_t *filter, va_list va);
/**
Print formated string. Some operating systems (Like NetBSD) do not
@ -153,7 +153,7 @@ int vfwprintf( FILE *f, const wchar_t *filter, va_list va );
strings and decimal numbers, position (%n), field width and
precision.
*/
int vswprintf( wchar_t *out, size_t n, const wchar_t *filter, va_list va );
int vswprintf(wchar_t *out, size_t n, const wchar_t *filter, va_list va);
#endif
@ -205,7 +205,7 @@ wchar_t *wcstok(wchar_t *wcs, const wchar_t *delim, wchar_t **ptr);
real wcwidth. Therefore, the fallback wcwidth assumes any printing
character takes up one column and anything else uses 0 columns.
*/
int wcwidth( wchar_t c );
int wcwidth(wchar_t c);
#endif
@ -215,14 +215,14 @@ int wcwidth( wchar_t c );
On other platforms, use what's detected at build time.
*/
#if __APPLE__ && __DARWIN_C_LEVEL >= 200809L
wchar_t *wcsdup_use_weak(const wchar_t *);
int wcscasecmp_use_weak(const wchar_t *, const wchar_t *);
#define wcsdup(a) wcsdup_use_weak((a))
#define wcscasecmp(a, b) wcscasecmp_use_weak((a), (b))
wchar_t *wcsdup_use_weak(const wchar_t *);
int wcscasecmp_use_weak(const wchar_t *, const wchar_t *);
#define wcsdup(a) wcsdup_use_weak((a))
#define wcscasecmp(a, b) wcscasecmp_use_weak((a), (b))
#else
#ifndef HAVE_WCSDUP
#ifndef HAVE_WCSDUP
/**
Create a duplicate string. Wide string version of strdup. Will
@ -230,9 +230,9 @@ int wcwidth( wchar_t c );
*/
wchar_t *wcsdup(const wchar_t *in);
#endif
#endif
#ifndef HAVE_WCSCASECMP
#ifndef HAVE_WCSCASECMP
/**
Case insensitive string compare function. Wide string version of
strcasecmp.
@ -244,9 +244,9 @@ wchar_t *wcsdup(const wchar_t *in);
fish and guaranteed to be a sane, english word. Using wcscasecmp on
a user-supplied string should be considered a bug.
*/
int wcscasecmp( const wchar_t *a, const wchar_t *b );
int wcscasecmp(const wchar_t *a, const wchar_t *b);
#endif
#endif
#endif //__APPLE__
@ -273,7 +273,7 @@ size_t wcslen(const wchar_t *in);
fish and guaranteed to be a sane, english word. Using wcsncasecmp on
a user-supplied string should be considered a bug.
*/
int wcsncasecmp( const wchar_t *a, const wchar_t *b, int count );
int wcsncasecmp(const wchar_t *a, const wchar_t *b, int count);
/**
Returns a newly allocated wide character string wich is a copy of
@ -290,7 +290,7 @@ int wcsncasecmp( const wchar_t *a, const wchar_t *b, int count );
Fallback for wcsndup function. Returns a copy of \c in, truncated
to a maximum length of \c c.
*/
wchar_t *wcsndup( const wchar_t *in, size_t c );
wchar_t *wcsndup(const wchar_t *in, size_t c);
#endif
@ -299,7 +299,7 @@ wchar_t *wcsndup( const wchar_t *in, size_t c );
a valid digit in the specified base, return -1. This is a helper
function for wcstol, but it is useful itself, so it is exported.
*/
long convert_digit( wchar_t d, int base );
long convert_digit(wchar_t d, int base);
#ifndef HAVE_WCSTOL
@ -312,8 +312,8 @@ long convert_digit( wchar_t d, int base );
supported.
*/
long wcstol(const wchar_t *nptr,
wchar_t **endptr,
int base);
wchar_t **endptr,
int base);
#endif
#ifndef HAVE_WCSLCAT
@ -329,7 +329,7 @@ long wcstol(const wchar_t *nptr,
and renamed to reflect this change.
*/
size_t wcslcat( wchar_t *dst, const wchar_t *src, size_t siz );
size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t siz);
#endif
#ifndef HAVE_WCSLCPY
@ -342,7 +342,7 @@ size_t wcslcat( wchar_t *dst, const wchar_t *src, size_t siz );
This is the OpenBSD strlcpy function, modified for wide characters,
and renamed to reflect this change.
*/
size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz);
#endif
@ -361,28 +361,28 @@ size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
*/
struct drand48_data
{
/**
Seed value
*/
unsigned int seed;
/**
Seed value
*/
unsigned int seed;
}
;
/**
Fallback implementation of lrand48_r. Internally uses rand_r, so it is pretty weak.
*/
int lrand48_r( struct drand48_data *buffer, long int *result );
int lrand48_r(struct drand48_data *buffer, long int *result);
/**
Fallback implementation of srand48_r, the seed function for lrand48_r.
*/
int srand48_r( long int seedval, struct drand48_data *buffer );
int srand48_r(long int seedval, struct drand48_data *buffer);
#endif
#ifndef HAVE_FUTIMES
int futimes( int fd, const struct timeval *times );
int futimes(int fd, const struct timeval *times);
#endif
@ -391,17 +391,17 @@ int futimes( int fd, const struct timeval *times );
/**
Fallback implementation of gettext. Just returns the original string.
*/
char * gettext( const char * msgid );
char * gettext(const char * msgid);
/**
Fallback implementation of bindtextdomain. Does nothing.
*/
char * bindtextdomain( const char * domainname, const char * dirname );
char * bindtextdomain(const char * domainname, const char * dirname);
/**
Fallback implementation of textdomain. Does nothing.
*/
char * textdomain( const char * domainname );
char * textdomain(const char * domainname);
#endif
@ -410,9 +410,9 @@ char * textdomain( const char * domainname );
/**
Fallback implementation of dcgettext. Just returns the original string.
*/
char * dcgettext ( const char * domainname,
const char * msgid,
int category );
char * dcgettext(const char * domainname,
const char * msgid,
int category);
#endif
@ -432,7 +432,7 @@ extern int _nl_msg_cat_cntr;
/**
Send specified signal to specified process group.
*/
int killpg( int pgr, int sig );
int killpg(int pgr, int sig);
#endif
@ -443,22 +443,22 @@ int killpg( int pgr, int sig );
*/
struct option
{
/**
Name of option
*/
const char *name;
/**
Flag
*/
int has_arg;
/**
Flag
*/
int *flag;
/**
Return value
*/
int val;
/**
Name of option
*/
const char *name;
/**
Flag
*/
int has_arg;
/**
Flag
*/
int *flag;
/**
Return value
*/
int val;
}
;
@ -475,10 +475,10 @@ struct option
#endif
int getopt_long(int argc,
char * const argv[],
const char *optstring,
const struct option *longopts,
int *longindex);
char * const argv[],
const char *optstring,
const struct option *longopts,
int *longindex);
#endif

632
fish.cpp
View file

@ -75,7 +75,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static bool has_suffix(const std::string &path, const char *suffix, bool ignore_case)
{
size_t pathlen = path.size(), suffixlen = strlen(suffix);
return pathlen >= suffixlen && ! (ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix);
return pathlen >= suffixlen && !(ignore_case ? strcasecmp : strcmp)(path.c_str() + pathlen - suffixlen, suffix);
}
/* Modifies the given path by calling realpath. Returns true if realpath succeeded, false otherwise */
@ -104,12 +104,12 @@ static std::string get_executable_path(const char *argv0)
uint32_t buffSize = sizeof buff;
if (0 == _NSGetExecutablePath(buff, &buffSize))
return std::string(buff);
/* Loop until we're big enough */
char *mbuff = (char *)malloc(buffSize);
while (0 > _NSGetExecutablePath(mbuff, &buffSize))
mbuff = (char *)realloc(mbuff, buffSize);
/* Return the string */
std::string result = mbuff;
free(mbuff);
@ -119,13 +119,13 @@ static std::string get_executable_path(const char *argv0)
{
/* On other Unixes, try /proc directory. This might be worth breaking out into macros. */
if (0 < readlink("/proc/self/exe", buff, sizeof buff) || // Linux
0 < readlink("/proc/curproc/file", buff, sizeof buff) || // BSD
0 < readlink("/proc/self/path/a.out", buff, sizeof buff)) // Solaris
0 < readlink("/proc/curproc/file", buff, sizeof buff) || // BSD
0 < readlink("/proc/self/path/a.out", buff, sizeof buff)) // Solaris
{
return std::string(buff);
}
}
/* Just return argv0, which probably won't work (i.e. it's not an absolute path or a path relative to the working directory, but instead something the caller found via $PATH). We'll eventually fall back to the compile time paths. */
return std::string(argv0 ? argv0 : "");
}
@ -137,9 +137,9 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
bool done = false;
std::string exec_path = get_executable_path(argv0);
if (get_realpath(exec_path))
{
{
#if __APPLE__
/* On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't link CF, use this lame approach to test it: see if the resolved path ends with /Contents/MacOS/fish, case insensitive since HFS+ usually is.
*/
if (! done)
@ -152,28 +152,28 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
wcstring wide_resolved_path = str2wcstring(exec_path);
wide_resolved_path.resize(exec_path.size() - suffixlen);
wide_resolved_path.append(L"/Contents/Resources/");
/* Append share, etc, doc */
paths.data = wide_resolved_path + L"share/fish";
paths.sysconf = wide_resolved_path + L"etc/fish";
paths.doc = wide_resolved_path + L"doc/fish";
/* But the bin_dir is the resolved_path, minus fish (aka the MacOS directory) */
paths.bin = str2wcstring(exec_path);
paths.bin.resize(paths.bin.size() - strlen("/fish"));
done = true;
}
}
#endif
if (! done)
{
/* The next check is that we are in a reloctable directory tree like this:
bin/fish
etc/fish
share/fish
Check it!
*/
const char *suffix = "/bin/fish";
@ -181,12 +181,12 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
{
wcstring base_path = str2wcstring(exec_path);
base_path.resize(base_path.size() - strlen(suffix));
paths.data = base_path + L"/share/fish";
paths.sysconf = base_path + L"/etc/fish";
paths.doc = base_path + L"/share/doc/fish";
paths.bin = base_path + L"/bin";
struct stat buf;
if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf))
{
@ -195,7 +195,7 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
}
}
}
if (! done)
{
/* Fall back to what got compiled in. */
@ -203,10 +203,10 @@ static struct config_paths_t determine_config_directory_paths(const char *argv0)
paths.sysconf = L"" SYSCONFDIR "/fish";
paths.doc = L"" DATADIR "/doc/fish";
paths.bin = L"" PREFIX "/bin";
done = true;
}
return paths;
}
@ -217,27 +217,27 @@ static int read_init(const struct config_paths_t &paths)
{
parser_t &parser = parser_t::principal_parser();
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.sysconf + 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);
/*
We need to get the configuration directory before we can source the user configuration file
*/
wcstring config_dir;
/*
If path_get_config returns false then we have no configuration directory
and no custom config to load.
*/
/*
We need to get the configuration directory before we can source the user configuration file
*/
wcstring config_dir;
/*
If path_get_config returns false then we have no configuration directory
and no custom config to load.
*/
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());
parser.eval( eval_buff, empty_ios, TOP );
}
return 1;
parser.eval(eval_buff, empty_ios, TOP);
}
return 1;
}
@ -245,164 +245,164 @@ static int read_init(const struct config_paths_t &paths)
Parse the argument list, return the index of the first non-switch
arguments.
*/
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 force_interactive=0;
while( 1 )
{
static struct option
long_options[] =
{
{
"command", required_argument, 0, 'c'
}
,
{
"debug-level", required_argument, 0, 'd'
}
,
{
"interactive", no_argument, 0, 'i'
}
,
{
"login", no_argument, 0, 'l'
}
,
{
"no-execute", no_argument, 0, 'n'
}
,
{
"profile", required_argument, 0, 'p'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = getopt_long( argc,
argv,
GETOPT_STRING,
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
{
case 0:
{
break;
}
case 'c':
{
*cmd_ptr = optarg;
is_interactive_session = 0;
break;
}
case 'd':
{
char *end;
long tmp;
int my_optind;
int force_interactive=0;
errno = 0;
tmp = strtol(optarg, &end, 10);
if( tmp >= 0 && tmp <=10 && !*end && !errno )
{
debug_level = (int)tmp;
}
else
{
debug( 0, _(L"Invalid value '%s' for debug level switch"), optarg );
exit_without_destructors(1);
}
break;
}
case 'h':
{
*cmd_ptr = "__fish_print_help fish";
break;
}
case 'i':
{
force_interactive = 1;
break;
}
case 'l':
{
is_login=1;
break;
}
case 'n':
{
no_exec=1;
break;
}
case 'p':
{
profile = optarg;
break;
}
case 'v':
{
fwprintf( stderr,
_(L"%s, version %s\n"),
PACKAGE_NAME,
PACKAGE_VERSION );
exit_without_destructors( 0 );
}
case '?':
{
exit_without_destructors( 1 );
}
}
}
while (1)
{
static struct option
long_options[] =
{
{
"command", required_argument, 0, 'c'
}
,
{
"debug-level", required_argument, 0, 'd'
}
,
{
"interactive", no_argument, 0, 'i'
}
,
{
"login", no_argument, 0, 'l'
}
,
{
"no-execute", no_argument, 0, 'n'
}
,
{
"profile", required_argument, 0, 'p'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
0, 0, 0, 0
}
}
;
my_optind = optind;
is_login |= (strcmp( argv[0], "-fish") == 0);
/*
We are an interactive session if we have not been given an
explicit command to execute, _and_ stdin is a tty.
*/
is_interactive_session &= (*cmd_ptr == 0);
is_interactive_session &= (my_optind == argc);
is_interactive_session &= isatty(STDIN_FILENO);
int opt_index = 0;
/*
We are also an interactive session if we have are forced-
*/
is_interactive_session |= force_interactive;
int opt = getopt_long(argc,
argv,
GETOPT_STRING,
long_options,
&opt_index);
return my_optind;
if (opt == -1)
break;
switch (opt)
{
case 0:
{
break;
}
case 'c':
{
*cmd_ptr = optarg;
is_interactive_session = 0;
break;
}
case 'd':
{
char *end;
long tmp;
errno = 0;
tmp = strtol(optarg, &end, 10);
if (tmp >= 0 && tmp <=10 && !*end && !errno)
{
debug_level = (int)tmp;
}
else
{
debug(0, _(L"Invalid value '%s' for debug level switch"), optarg);
exit_without_destructors(1);
}
break;
}
case 'h':
{
*cmd_ptr = "__fish_print_help fish";
break;
}
case 'i':
{
force_interactive = 1;
break;
}
case 'l':
{
is_login=1;
break;
}
case 'n':
{
no_exec=1;
break;
}
case 'p':
{
profile = optarg;
break;
}
case 'v':
{
fwprintf(stderr,
_(L"%s, version %s\n"),
PACKAGE_NAME,
PACKAGE_VERSION);
exit_without_destructors(0);
}
case '?':
{
exit_without_destructors(1);
}
}
}
my_optind = optind;
is_login |= (strcmp(argv[0], "-fish") == 0);
/*
We are an interactive session if we have not been given an
explicit command to execute, _and_ stdin is a tty.
*/
is_interactive_session &= (*cmd_ptr == 0);
is_interactive_session &= (my_optind == argc);
is_interactive_session &= isatty(STDIN_FILENO);
/*
We are also an interactive session if we have are forced-
*/
is_interactive_session |= force_interactive;
return my_optind;
}
/**
@ -410,70 +410,70 @@ static int fish_parse_opt( int argc, char **argv, const char **cmd_ptr )
parses commands from stdin or files, depending on arguments
*/
static wcstring full_escape( const wchar_t *in )
static wcstring full_escape(const wchar_t *in)
{
wcstring out;
for( ; *in; in++ )
{
if( *in < 32 )
{
append_format( out, L"\\x%.2x", *in );
}
else if( *in < 128 )
{
out.push_back(*in);
}
else if( *in < 65536 )
{
append_format( out, L"\\u%.4x", *in );
}
else
{
append_format( out, L"\\U%.8x", *in );
}
}
return out;
wcstring out;
for (; *in; in++)
{
if (*in < 32)
{
append_format(out, L"\\x%.2x", *in);
}
else if (*in < 128)
{
out.push_back(*in);
}
else if (*in < 65536)
{
append_format(out, L"\\u%.4x", *in);
}
else
{
append_format(out, L"\\U%.8x", *in);
}
}
return out;
}
extern int g_fork_count;
int main( int argc, char **argv )
{
int res=1;
const char *cmd=0;
int my_optind=0;
int main(int argc, char **argv)
{
int res=1;
const char *cmd=0;
int my_optind=0;
set_main_thread();
set_main_thread();
setup_fork_guards();
save_term_foreground_process_group();
wsetlocale( LC_ALL, L"" );
is_interactive_session=1;
program_name=L"fish";
wsetlocale(LC_ALL, L"");
is_interactive_session=1;
program_name=L"fish";
//struct stat 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
*/
if( is_interactive_session && no_exec)
{
debug( 1, _(L"Can not use the no-execute mode when running an interactive session") );
no_exec = 0;
}
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
proc_init();
event_init();
wutil_init();
builtin_init();
function_init();
env_init(&paths);
reader_init();
history_init();
/*
No-exec is prohibited when in interactive mode
*/
if (is_interactive_session && no_exec)
{
debug(1, _(L"Can not use the no-execute mode when running an interactive session"));
no_exec = 0;
}
const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
proc_init();
event_init();
wutil_init();
builtin_init();
function_init();
env_init(&paths);
reader_init();
history_init();
parser_t &parser = parser_t::principal_parser();
@ -481,92 +481,92 @@ int main( int argc, char **argv )
printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
const io_chain_t empty_ios;
if( read_init(paths) )
{
if( cmd != 0 )
{
wchar_t *cmd_wcs = str2wcs( cmd );
res = parser.eval( cmd_wcs, empty_ios, TOP );
free(cmd_wcs);
reader_exit(0, 0);
}
else
{
if( my_optind == argc )
{
res = reader_read( STDIN_FILENO, empty_ios );
}
else
{
char **ptr;
char *file = *(argv+(my_optind++));
int i;
int fd;
wchar_t *rel_filename, *abs_filename;
if (read_init(paths))
{
if (cmd != 0)
{
wchar_t *cmd_wcs = str2wcs(cmd);
res = parser.eval(cmd_wcs, empty_ios, TOP);
free(cmd_wcs);
reader_exit(0, 0);
}
else
{
if (my_optind == argc)
{
res = reader_read(STDIN_FILENO, empty_ios);
}
else
{
char **ptr;
char *file = *(argv+(my_optind++));
int i;
int fd;
wchar_t *rel_filename, *abs_filename;
if ((fd = open(file, O_RDONLY)) == -1)
{
wperror(L"open");
return 1;
}
if( ( fd = open(file, O_RDONLY) ) == -1 )
{
wperror( L"open" );
return 1;
}
// OK to not do this atomically since we cannot have gone multithreaded yet
set_cloexec(fd);
if( *(argv+my_optind))
{
if (*(argv+my_optind))
{
wcstring sb;
for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ )
{
if( i != 1 )
sb.append( ARRAY_SEP_STR );
sb.append( str2wcstring( *ptr ));
}
env_set( L"argv", sb.c_str(), 0 );
}
for (i=1,ptr = argv+my_optind; *ptr; i++, ptr++)
{
if (i != 1)
sb.append(ARRAY_SEP_STR);
sb.append(str2wcstring(*ptr));
}
rel_filename = str2wcs( file );
abs_filename = wrealpath( rel_filename, 0 );
env_set(L"argv", sb.c_str(), 0);
}
if( !abs_filename )
{
abs_filename = wcsdup(rel_filename);
}
rel_filename = str2wcs(file);
abs_filename = wrealpath(rel_filename, 0);
reader_push_current_filename( intern( abs_filename ) );
free( rel_filename );
free( abs_filename );
if (!abs_filename)
{
abs_filename = wcsdup(rel_filename);
}
res = reader_read( fd, empty_ios );
reader_push_current_filename(intern(abs_filename));
free(rel_filename);
free(abs_filename);
res = reader_read(fd, empty_ios);
if (res)
{
debug(1,
_(L"Error while reading file %ls\n"),
reader_current_filename()?reader_current_filename(): _(L"Standard input"));
}
reader_pop_current_filename();
}
}
}
proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), res);
if( res )
{
debug( 1,
_(L"Error while reading file %ls\n"),
reader_current_filename()?reader_current_filename(): _(L"Standard input") );
}
reader_pop_current_filename();
}
}
}
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
restore_term_foreground_process_group();
history_destroy();
proc_destroy();
builtin_destroy();
reader_destroy();
parser.destroy();
wutil_destroy();
event_destroy();
env_destroy();
history_destroy();
proc_destroy();
builtin_destroy();
reader_destroy();
parser.destroy();
wutil_destroy();
event_destroy();
env_destroy();
if (g_log_forks)
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();
}

View file

@ -49,30 +49,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/**
Read the entire contents of a file into the specified string
*/
static void read_file( FILE *f, wcstring &b )
static void read_file(FILE *f, wcstring &b)
{
while( 1 )
{
errno=0;
wint_t c = fgetwc( f );
if( c == WEOF )
while (1)
{
if( errno )
{
wperror(L"fgetwc");
exit(1);
}
errno=0;
wint_t c = fgetwc(f);
if (c == WEOF)
{
if (errno)
{
wperror(L"fgetwc");
exit(1);
}
break;
break;
}
b.push_back((wchar_t)c);
}
b.push_back((wchar_t)c);
}
}
/**
Insert the specified number of tabs into the output buffer
*/
static void insert_tabs( wcstring &out, int indent )
static void insert_tabs(wcstring &out, int indent)
{
if (indent > 0)
out.append((size_t)indent, L'\t');
@ -82,184 +82,193 @@ static void insert_tabs( wcstring &out, int indent )
/**
Indent the specified input
*/
static int indent( wcstring &out, const wcstring &in, int flags )
static int indent(wcstring &out, const wcstring &in, int flags)
{
tokenizer tok;
int res=0;
int is_command = 1;
int indent = 0;
int do_indent = 1;
int prev_type = 0;
int prev_prev_type = 0;
tokenizer tok;
int res=0;
int is_command = 1;
int indent = 0;
int do_indent = 1;
int 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 ) )
{
int type = tok_last_type( &tok );
wchar_t *last = tok_last( &tok );
switch( type )
for (; tok_has_next(&tok); tok_next(&tok))
{
case TOK_STRING:
{
if( is_command )
int type = tok_last_type(&tok);
wchar_t *last = tok_last(&tok);
switch (type)
{
int next_indent = indent;
is_command = 0;
wcstring unesc = last;
unescape_string(unesc, UNESCAPE_SPECIAL);
if( parser_keywords_is_block(unesc))
{
next_indent++;
}
else if (unesc == L"else")
{
indent--;
}
/* case should have the same indent level as switch*/
else if (unesc == L"case")
{
indent--;
}
else if (unesc == L"end")
{
indent--;
next_indent--;
}
if( do_indent && flags && prev_type != TOK_PIPE )
{
insert_tabs( out, indent );
}
append_format(out, L"%ls", last );
indent = next_indent;
}
else
case TOK_STRING:
{
if ( prev_type != TOK_REDIRECT_FD )
out.append( L" " );
out.append( last );
}
if (is_command)
{
int next_indent = indent;
is_command = 0;
break;
}
wcstring unesc = last;
unescape_string(unesc, UNESCAPE_SPECIAL);
case TOK_END:
{
if( prev_type != TOK_END || prev_prev_type != TOK_END )
out.append( L"\n" );
do_indent = 1;
is_command = 1;
break;
}
if (parser_keywords_is_block(unesc))
{
next_indent++;
}
else if (unesc == L"else")
{
indent--;
}
/* case should have the same indent level as switch*/
else if (unesc == L"case")
{
indent--;
}
else if (unesc == L"end")
{
indent--;
next_indent--;
}
case TOK_PIPE:
{
out.append( L" " );
if ( last[0] == '2' && !last[1] ) {
out.append( L"^" );
} else if ( last[0] != '1' || last[1] ) {
out.append( last);
out.append( L">" );
}
out.append( L" | " );
is_command = 1;
break;
}
case TOK_REDIRECT_OUT:
{
out.append( L" " );
if ( wcscmp( last, L"2" ) == 0 ) {
out.append( L"^" );
} else {
if ( wcscmp( last, L"1" ) != 0 )
out.append( last );
out.append( L"> " );
}
break;
}
if (do_indent && flags && prev_type != TOK_PIPE)
{
insert_tabs(out, indent);
}
case TOK_REDIRECT_APPEND:
{
out.append( L" " );
if ( wcscmp( last, L"2" ) == 0 ) {
out.append( L"^^" );
} else {
if ( wcscmp( last, L"1" ) != 0 )
out.append( last );
out.append( L">> " );
}
break;
}
append_format(out, L"%ls", last);
case TOK_REDIRECT_IN:
{
out.append( L" " );
if ( wcscmp( last, L"0" ) != 0 )
out.append( last );
out.append( L"< " );
break;
}
indent = next_indent;
}
else
{
if (prev_type != TOK_REDIRECT_FD)
out.append(L" ");
out.append(last);
}
case TOK_REDIRECT_FD:
{
out.append( L" " );
if ( wcscmp( last, L"1" ) != 0 )
out.append( last );
out.append( L">& " );
break;
}
case TOK_BACKGROUND:
{
out.append( L"&\n" );
do_indent = 1;
is_command = 1;
break;
}
case TOK_COMMENT:
{
if( do_indent && flags)
case TOK_END:
{
insert_tabs( out, indent );
if (prev_type != TOK_END || prev_prev_type != TOK_END)
out.append(L"\n");
do_indent = 1;
is_command = 1;
break;
}
append_format( out, L"%ls", last );
do_indent = 1;
break;
}
case TOK_PIPE:
{
out.append(L" ");
if (last[0] == '2' && !last[1])
{
out.append(L"^");
}
else if (last[0] != '1' || last[1])
{
out.append(last);
out.append(L">");
}
out.append(L" | ");
is_command = 1;
break;
}
case TOK_REDIRECT_OUT:
{
out.append(L" ");
if (wcscmp(last, L"2") == 0)
{
out.append(L"^");
}
else
{
if (wcscmp(last, L"1") != 0)
out.append(last);
out.append(L"> ");
}
break;
}
case TOK_REDIRECT_APPEND:
{
out.append(L" ");
if (wcscmp(last, L"2") == 0)
{
out.append(L"^^");
}
else
{
if (wcscmp(last, L"1") != 0)
out.append(last);
out.append(L">> ");
}
break;
}
case TOK_REDIRECT_IN:
{
out.append(L" ");
if (wcscmp(last, L"0") != 0)
out.append(last);
out.append(L"< ");
break;
}
case TOK_REDIRECT_FD:
{
out.append(L" ");
if (wcscmp(last, L"1") != 0)
out.append(last);
out.append(L">& ");
break;
}
case TOK_BACKGROUND:
{
out.append(L"&\n");
do_indent = 1;
is_command = 1;
break;
}
case TOK_COMMENT:
{
if (do_indent && flags)
{
insert_tabs(out, indent);
}
append_format(out, L"%ls", last);
do_indent = 1;
break;
}
default:
{
debug(0, L"Unknown token '%ls'", last);
exit(1);
}
}
prev_prev_type = prev_type;
prev_type = type;
default:
{
debug( 0, L"Unknown token '%ls'", last );
exit(1);
}
}
prev_prev_type = prev_type;
prev_type = type;
tok_destroy(&tok);
}
tok_destroy( &tok );
return res;
return res;
}
/**
Remove any prefix and suffix newlines from the specified
string.
*/
static void trim( wcstring &str )
static void trim(wcstring &str)
{
if (str.empty())
return;
@ -277,107 +286,107 @@ static void trim( wcstring &str )
/**
The main mathod. Run the program.
*/
int main( int argc, char **argv )
int main(int argc, char **argv)
{
int do_indent=1;
set_main_thread();
int do_indent=1;
set_main_thread();
setup_fork_guards();
wsetlocale( LC_ALL, L"" );
program_name=L"fish_indent";
wsetlocale(LC_ALL, L"");
program_name=L"fish_indent";
while( 1 )
{
static struct option
long_options[] =
{
{
"no-indent", no_argument, 0, 'i'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = getopt_long( argc,
argv,
GETOPT_STRING,
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
while (1)
{
case 0:
{
break;
}
static struct option
long_options[] =
{
{
"no-indent", no_argument, 0, 'i'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
0, 0, 0, 0
}
}
;
case 'h':
{
print_help( "fish_indent", 1 );
exit( 0 );
break;
}
int opt_index = 0;
case 'v':
{
fwprintf( stderr,
_(L"%ls, version %s\n"),
program_name,
PACKAGE_VERSION );
exit( 0 );
}
int opt = getopt_long(argc,
argv,
GETOPT_STRING,
long_options,
&opt_index);
case 'i':
{
do_indent = 0;
break;
}
if (opt == -1)
break;
switch (opt)
{
case 0:
{
break;
}
case 'h':
{
print_help("fish_indent", 1);
exit(0);
break;
}
case 'v':
{
fwprintf(stderr,
_(L"%ls, version %s\n"),
program_name,
PACKAGE_VERSION);
exit(0);
}
case 'i':
{
do_indent = 0;
break;
}
case '?':
{
exit( 1 );
}
case '?':
{
exit(1);
}
}
}
}
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);
fwprintf( stdout, L"%ls", sb_out.c_str() );
}
else
{
/*
Indenting failed - print original input
*/
fwprintf( stdout, L"%ls", sb_in.c_str() );
}
fwprintf(stdout, L"%ls", sb_out.c_str());
}
else
{
/*
Indenting failed - print original input
*/
fwprintf(stdout, L"%ls", sb_in.c_str());
}
wutil_destroy();
wutil_destroy();
return 0;
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1074
fishd.cpp

File diff suppressed because it is too large Load diff

View file

@ -48,7 +48,8 @@ static function_map_t loaded_functions;
static pthread_mutex_t functions_lock;
/* Autoloader for functions */
class function_autoload_t : public autoload_t {
class function_autoload_t : public autoload_t
{
public:
function_autoload_t();
virtual void command_removed(const wcstring &cmd);
@ -58,8 +59,8 @@ static function_autoload_t function_autoloader;
/** Constructor */
function_autoload_t::function_autoload_t() : autoload_t(L"fish_function_path",
internal_function_scripts,
sizeof internal_function_scripts / sizeof *internal_function_scripts)
internal_function_scripts,
sizeof internal_function_scripts / sizeof *internal_function_scripts)
{
}
@ -67,7 +68,8 @@ function_autoload_t::function_autoload_t() : autoload_t(L"fish_function_path",
static bool function_remove_ignore_autoload(const wcstring &name);
/** Callback when an autoloaded function is removed */
void function_autoload_t::command_removed(const wcstring &cmd) {
void function_autoload_t::command_removed(const wcstring &cmd)
{
function_remove_ignore_autoload(cmd);
}
@ -85,65 +87,66 @@ static bool is_autoload = false;
Make sure that if the specified function is a dynamically loaded
function, it has been fully loaded.
*/
static int load( const wcstring &name )
static int load(const wcstring &name)
{
ASSERT_IS_MAIN_THREAD();
scoped_lock lock(functions_lock);
bool was_autoload = is_autoload;
int res;
bool was_autoload = is_autoload;
int res;
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 */
return 0;
return 0;
}
is_autoload = true;
res = function_autoloader.load( name, true );
is_autoload = was_autoload;
return res;
is_autoload = true;
res = function_autoloader.load(name, true);
is_autoload = was_autoload;
return res;
}
/**
Insert a list of all dynamically loaded functions into the
specified list.
*/
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())
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;
tokenize_variable_array( path_var, path_list );
for( i=0; i<path_list.size(); i++ )
{
const wcstring &ndir_str = path_list.at(i);
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
DIR *dir = wopendir( ndir );
if( !dir )
continue;
wcstring name;
while (wreaddir(dir, name))
tokenize_variable_array(path_var, path_list);
for (i=0; i<path_list.size(); i++)
{
const wchar_t *fn = name.c_str();
const wchar_t *suffix;
if( !get_hidden && fn[0] == L'_' )
continue;
const wcstring &ndir_str = path_list.at(i);
const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
DIR *dir = wopendir(ndir);
if (!dir)
continue;
suffix = wcsrchr( fn, L'.' );
if( suffix && (wcscmp( suffix, L".fish" ) == 0 ) )
{
wcstring name;
while (wreaddir(dir, name))
{
const wchar_t *fn = name.c_str();
const wchar_t *suffix;
if (!get_hidden && fn[0] == L'_')
continue;
suffix = wcsrchr(fn, L'.');
if (suffix && (wcscmp(suffix, L".fish") == 0))
{
wcstring name(fn, suffix - fn);
names.insert(name);
}
}
}
closedir(dir);
}
closedir(dir);
}
}
void function_init()
@ -178,16 +181,16 @@ function_info_t::function_info_t(const function_info_t &data, const wchar_t *fil
{
}
void function_add( const function_data_t &data, const parser_t &parser )
void function_add(const function_data_t &data, const parser_t &parser)
{
ASSERT_IS_MAIN_THREAD();
CHECK( ! data.name.empty(), );
CHECK( data.definition, );
scoped_lock lock(functions_lock);
CHECK(! data.name.empty(),);
CHECK(data.definition,);
scoped_lock lock(functions_lock);
/* Remove the old function */
function_remove( data.name );
function_remove(data.name);
/* Create and store a new function */
@ -197,25 +200,25 @@ void function_add( const function_data_t &data, const parser_t &parser )
loaded_functions.insert(new_pair);
/* Add event handlers */
for( std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter )
{
event_add_handler( &*iter );
}
for (std::vector<event_t>::const_iterator iter = data.events.begin(); iter != data.events.end(); ++iter)
{
event_add_handler(&*iter);
}
}
int function_exists( const wcstring &cmd )
int function_exists(const wcstring &cmd)
{
if( parser_keywords_is_reserved(cmd) )
return 0;
if (parser_keywords_is_reserved(cmd))
return 0;
scoped_lock lock(functions_lock);
load(cmd);
return loaded_functions.find(cmd) != loaded_functions.end();
}
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) )
return 0;
if (parser_keywords_is_reserved(cmd))
return 0;
scoped_lock lock(functions_lock);
return loaded_functions.find(cmd) != loaded_functions.end() || function_autoloader.can_load(cmd, vars);
}
@ -225,19 +228,20 @@ static bool function_remove_ignore_autoload(const wcstring &name)
scoped_lock lock(functions_lock);
bool erased = (loaded_functions.erase(name) > 0);
if (erased) {
if (erased)
{
event_t ev(EVENT_ANY);
ev.function_name=name;
event_remove( &ev );
event_remove(&ev);
}
return erased;
}
void function_remove( const wcstring &name )
void function_remove(const wcstring &name)
{
if (function_remove_ignore_autoload(name))
function_autoloader.unload( name );
function_autoloader.unload(name);
}
static const function_info_t *function_get(const wcstring &name)
@ -246,9 +250,12 @@ static const function_info_t *function_get(const wcstring &name)
// We need a way to correctly check if a lock is locked (or better yet, make our lock non-recursive)
//ASSERT_IS_LOCKED(functions_lock);
function_map_t::iterator iter = loaded_functions.find(name);
if (iter == loaded_functions.end()) {
if (iter == loaded_functions.end())
{
return NULL;
} else {
}
else
{
return &iter->second;
}
}
@ -257,7 +264,8 @@ bool function_get_definition(const wcstring &name, wcstring *out_definition)
{
scoped_lock lock(functions_lock);
const function_info_t *func = function_get(name);
if (func && out_definition) {
if (func && out_definition)
{
out_definition->assign(func->definition);
}
return func != NULL;
@ -283,20 +291,24 @@ bool function_get_desc(const wcstring &name, wcstring *out_desc)
/* Empty length string goes to NULL */
scoped_lock lock(functions_lock);
const function_info_t *func = function_get(name);
if (out_desc && func && ! func->description.empty()) {
if (out_desc && func && ! func->description.empty())
{
out_desc->assign(_(func->description.c_str()));
return true;
} else {
}
else
{
return false;
}
}
void function_set_desc(const wcstring &name, const wcstring &desc)
{
load(name);
load(name);
scoped_lock lock(functions_lock);
function_map_t::iterator iter = loaded_functions.find(name);
if (iter != loaded_functions.end()) {
if (iter != loaded_functions.end())
{
iter->second.description = desc;
}
}
@ -306,27 +318,30 @@ bool function_copy(const wcstring &name, const wcstring &new_name)
bool result = false;
scoped_lock lock(functions_lock);
function_map_t::const_iterator iter = loaded_functions.find(name);
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.
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.
const function_map_t::value_type new_pair(new_name, function_info_t(iter->second, NULL, 0, false));
loaded_functions.insert(new_pair);
result = true;
}
return result;
return result;
}
wcstring_list_t function_get_names(int get_hidden)
{
std::set<wcstring> names;
scoped_lock lock(functions_lock);
autoload_names(names, get_hidden);
autoload_names(names, get_hidden);
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)
{
const wcstring &name = iter->first;
/* Maybe skip hidden */
if (! get_hidden) {
if (! get_hidden)
{
if (name.empty() || name.at(0) == L'_') continue;
}
names.insert(name);

View file

@ -28,34 +28,35 @@ class env_vars_snapshot_t;
*/
struct function_data_t
{
/**
Name of function
*/
wcstring name;
/**
Description of function
*/
wcstring description;
/**
Function definition
*/
wchar_t *definition;
/**
List of all event handlers for this function
*/
std::vector<event_t> events;
/**
List of all named arguments for this function
*/
wcstring_list_t named_arguments;
/**
Set to non-zero if invoking this function shadows the variables
of the underlying function.
*/
int shadows;
/**
Name of function
*/
wcstring name;
/**
Description of function
*/
wcstring description;
/**
Function definition
*/
wchar_t *definition;
/**
List of all event handlers for this function
*/
std::vector<event_t> events;
/**
List of all named arguments for this function
*/
wcstring_list_t named_arguments;
/**
Set to non-zero if invoking this function shadows the variables
of the underlying function.
*/
int shadows;
};
class function_info_t {
class function_info_t
{
public:
/** Constructs relevant information from the function_data */
function_info_t(const function_data_t &data, const wchar_t *filename, int def_offset, bool autoload);
@ -69,20 +70,20 @@ public:
/** Function description. Only the description may be changed after the function is created. */
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;
/** Line where definition started */
const int definition_offset;
/** Line where definition started */
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;
/** Flag for specifying that this function was automatically loaded */
/** Flag for specifying that this function was automatically loaded */
const bool is_autoload;
/** Set to true if invoking this function shadows the variables of the underlying function. */
const bool shadows;
/** Set to true if invoking this function shadows the variables of the underlying function. */
const bool shadows;
};
@ -92,46 +93,46 @@ public:
void function_init();
/** Add a function. */
void function_add( const function_data_t &data, const parser_t &parser );
void function_add(const function_data_t &data, const parser_t &parser);
/**
Remove the function with the specified name.
*/
void function_remove( const wcstring &name );
void function_remove(const wcstring &name);
/**
Returns by reference the definition of the function with the name \c name.
Returns true if successful, false if no function with the given name exists.
*/
bool function_get_definition( const wcstring &name, wcstring *out_definition );
bool function_get_definition(const wcstring &name, wcstring *out_definition);
/**
Returns by reference the description of the function with the name \c name.
Returns true if the function exists and has a nonempty description, false if it does not.
*/
bool function_get_desc( const wcstring &name, wcstring *out_desc );
bool function_get_desc(const wcstring &name, wcstring *out_desc);
/**
Sets the description of the function with the name \c name.
*/
void function_set_desc( const wcstring &name, const wcstring &desc );
void function_set_desc(const wcstring &name, const wcstring &desc);
/**
Returns true if the function with the name name exists.
*/
int function_exists( const wcstring &name );
int function_exists(const wcstring &name);
/**
Returns true if the function with the name name exists, without triggering autoload.
*/
int function_exists_no_autoload( const wcstring &name, const env_vars_snapshot_t &vars );
int function_exists_no_autoload(const wcstring &name, const env_vars_snapshot_t &vars);
/**
Returns all function names.
\param get_hidden whether to include hidden functions, i.e. ones starting with an underscore
*/
wcstring_list_t function_get_names( int get_hidden );
wcstring_list_t function_get_names(int get_hidden);
/**
Returns tha absolute path of the file where the specified function
@ -142,7 +143,7 @@ wcstring_list_t function_get_names( int get_hidden );
This returns an intern'd string.
*/
const wchar_t *function_get_definition_file( const wcstring &name );
const wchar_t *function_get_definition_file(const wcstring &name);
/**
Returns the linenumber where the definition of the specified
@ -151,23 +152,23 @@ const wchar_t *function_get_definition_file( const wcstring &name );
This function does not autoload functions, it will only work on
functions that have already been defined.
*/
int function_get_definition_offset( const wcstring &name );
int function_get_definition_offset(const wcstring &name);
/**
Returns a list of all named arguments of the specified function.
*/
wcstring_list_t function_get_named_arguments( const wcstring &name );
wcstring_list_t function_get_named_arguments(const wcstring &name);
/**
Creates a new function using the same definition as the specified function.
Returns true if copy is successful.
*/
bool function_copy( const wcstring &name, const wcstring &new_name );
bool function_copy(const wcstring &name, const wcstring &new_name);
/**
Returns whether this function shadows variables of the underlying function
*/
int function_get_shadows( const wcstring &name );
int function_get_shadows(const wcstring &name);
#endif

File diff suppressed because it is too large Load diff

View file

@ -83,7 +83,7 @@ struct file_detection_context_t;
\param pos the cursor position. Used for quote matching, etc.
\param error a list in which a description of each error will be inserted. May be 0, in whcich case no error descriptions will be generated.
*/
void highlight_shell( const wcstring &buffstr, std::vector<int> &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars );
void highlight_shell(const wcstring &buffstr, std::vector<int> &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars);
/**
Perform syntax highlighting for the text in buff. Matching quotes and paranthesis are highlighted. The result is
@ -95,7 +95,7 @@ void highlight_shell( const wcstring &buffstr, std::vector<int> &color, size_t p
\param pos the cursor position. Used for quote matching, etc.
\param error a list in which a description of each error will be inserted. May be 0, in whcich case no error descriptions will be generated.
*/
void highlight_universal( const wcstring &buffstr, std::vector<int> &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars );
void highlight_universal(const wcstring &buffstr, std::vector<int> &color, size_t pos, wcstring_list_t *error, const env_vars_snapshot_t &vars);
/**
Translate from HIGHLIGHT_* to FISH_COLOR_* according to environment
@ -107,7 +107,7 @@ void highlight_universal( const wcstring &buffstr, std::vector<int> &color, size
call to highlight_get_color( HIGHLIGHT_ERROR) will return
FISH_COLOR_RED.
*/
rgb_color_t highlight_get_color( int highlight, bool is_background );
rgb_color_t highlight_get_color(int highlight, bool is_background);
/** Given a command 'str' from the history, try to determine whether we ought to suggest it by specially recognizing the command.
Returns true if we validated the command. If so, returns by reference whether the suggestion is valid or not.
@ -122,7 +122,8 @@ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_di
This is used only internally to this file, and is exposed only for testing.
*/
enum {
enum
{
/* The path must be to a directory */
PATH_REQUIRE_DIR = 1 << 0,

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,8 @@
typedef std::vector<wcstring> path_list_t;
enum history_search_type_t {
enum history_search_type_t
{
/** The history searches for strings containing the given string */
HISTORY_SEARCH_TYPE_CONTAINS,
@ -23,39 +24,53 @@ enum history_search_type_t {
HISTORY_SEARCH_TYPE_PREFIX
};
class history_item_t {
class history_item_t
{
friend class history_t;
friend class history_lru_node_t;
friend class history_tests_t;
private:
private:
explicit history_item_t(const wcstring &);
explicit history_item_t(const wcstring &, time_t, const path_list_t &paths = path_list_t());
/** Attempts to merge two compatible history items together */
bool merge(const history_item_t &item);
/** The actual contents of the entry */
wcstring contents;
/** The actual contents of the entry */
wcstring contents;
/** Original creation time for the entry */
time_t creation_timestamp;
/** Original creation time for the entry */
time_t creation_timestamp;
/** Paths that we require to be valid for this item to be autosuggested */
path_list_t required_paths;
public:
const wcstring &str() const { return contents; }
bool empty() const { return contents.empty(); }
public:
const wcstring &str() const
{
return contents;
}
bool empty() const
{
return contents.empty();
}
/* Whether our contents matches a search term. */
bool matches_search(const wcstring &term, enum history_search_type_t type) const;
time_t timestamp() const { return creation_timestamp; }
time_t timestamp() const
{
return creation_timestamp;
}
const path_list_t &get_required_paths() const { return required_paths; }
const path_list_t &get_required_paths() const
{
return required_paths;
}
bool operator==(const history_item_t &other) const {
bool operator==(const history_item_t &other) const
{
return contents == other.contents &&
creation_timestamp == other.creation_timestamp &&
required_paths == other.required_paths;
@ -63,13 +78,15 @@ class history_item_t {
};
/* The type of file that we mmap'd */
enum history_file_type_t {
enum history_file_type_t
{
history_type_unknown,
history_type_fish_2_0,
history_type_fish_1_x
};
class history_t {
class history_t
{
friend class history_tests_t;
private:
/** No copying */
@ -91,23 +108,23 @@ private:
/** Internal function */
void clear_file_state();
/** The name of this list. Used for picking a suitable filename and for switching modes. */
const wcstring name;
/** The name of this list. Used for picking a suitable filename and for switching modes. */
const wcstring name;
/** New items. */
std::vector<history_item_t> new_items;
/** New items. */
std::vector<history_item_t> new_items;
/** Deleted item contents. */
std::set<wcstring> deleted_items;
std::set<wcstring> deleted_items;
/** How many items we've added without saving */
size_t unsaved_item_count;
/** How many items we've added without saving */
size_t unsaved_item_count;
/** The mmaped region for the history file */
const char *mmap_start;
/** The mmaped region for the history file */
const char *mmap_start;
/** The size of the mmap'd region */
size_t mmap_length;
/** The size of the mmap'd region */
size_t mmap_length;
/** The type of file we mmap'd */
history_file_type_t mmap_type;
@ -115,8 +132,8 @@ private:
/** Timestamp of when this history was created */
const time_t birth_timestamp;
/** Timestamp of last save */
time_t save_timestamp;
/** Timestamp of last save */
time_t save_timestamp;
void populate_from_mmap(void);
@ -174,7 +191,8 @@ public:
bool is_deleted(const history_item_t &item) const;
};
class history_search_t {
class history_search_t
{
/** The history in which we are searching */
history_t * history;
@ -197,10 +215,13 @@ class history_search_t {
bool should_skip_match(const wcstring &str) const;
public:
public:
/** Gets the search term */
const wcstring &get_term() const { return term; }
const wcstring &get_term() const
{
return term;
}
/** Sets additional string matches to skip */
void skip_matches(const wcstring_list_t &skips);
@ -262,7 +283,8 @@ void history_destroy();
void history_sanity_check();
/* A helper class for threaded detection of paths */
struct file_detection_context_t {
struct file_detection_context_t
{
/* Constructor */
file_detection_context_t(history_t *hist, const wcstring &cmd);

974
input.cpp

File diff suppressed because it is too large Load diff

88
input.h
View file

@ -17,40 +17,40 @@ inputrc information for key bindings.
*/
enum
{
R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */
R_END_OF_LINE,
R_FORWARD_CHAR,
R_BACKWARD_CHAR,
R_FORWARD_WORD,
R_BACKWARD_WORD,
R_HISTORY_SEARCH_BACKWARD,
R_HISTORY_SEARCH_FORWARD,
R_DELETE_CHAR,
R_BACKWARD_DELETE_CHAR,
R_KILL_LINE,
R_YANK,
R_YANK_POP,
R_COMPLETE,
R_BEGINNING_OF_HISTORY,
R_END_OF_HISTORY,
R_BACKWARD_KILL_LINE,
R_KILL_WHOLE_LINE,
R_KILL_WORD,
R_BACKWARD_KILL_WORD,
R_DUMP_FUNCTIONS,
R_HISTORY_TOKEN_SEARCH_BACKWARD,
R_HISTORY_TOKEN_SEARCH_FORWARD,
R_SELF_INSERT,
R_VI_ARG_DIGIT,
R_VI_DELETE_TO,
R_EXECUTE,
R_BEGINNING_OF_BUFFER,
R_END_OF_BUFFER,
R_REPAINT,
R_UP_LINE,
R_DOWN_LINE,
R_SUPPRESS_AUTOSUGGESTION,
R_ACCEPT_AUTOSUGGESTION
R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */
R_END_OF_LINE,
R_FORWARD_CHAR,
R_BACKWARD_CHAR,
R_FORWARD_WORD,
R_BACKWARD_WORD,
R_HISTORY_SEARCH_BACKWARD,
R_HISTORY_SEARCH_FORWARD,
R_DELETE_CHAR,
R_BACKWARD_DELETE_CHAR,
R_KILL_LINE,
R_YANK,
R_YANK_POP,
R_COMPLETE,
R_BEGINNING_OF_HISTORY,
R_END_OF_HISTORY,
R_BACKWARD_KILL_LINE,
R_KILL_WHOLE_LINE,
R_KILL_WORD,
R_BACKWARD_KILL_WORD,
R_DUMP_FUNCTIONS,
R_HISTORY_TOKEN_SEARCH_BACKWARD,
R_HISTORY_TOKEN_SEARCH_FORWARD,
R_SELF_INSERT,
R_VI_ARG_DIGIT,
R_VI_DELETE_TO,
R_EXECUTE,
R_BEGINNING_OF_BUFFER,
R_END_OF_BUFFER,
R_REPAINT,
R_UP_LINE,
R_DOWN_LINE,
R_SUPPRESS_AUTOSUGGESTION,
R_ACCEPT_AUTOSUGGESTION
}
;
@ -87,7 +87,7 @@ wint_t input_readch();
characters that input_readch will return before actually reading from fd
0.
*/
void input_unreadch( wint_t ch );
void input_unreadch(wint_t ch);
/**
@ -96,22 +96,22 @@ void input_unreadch( wint_t ch );
\param sequence the sequence to bind
\param command an input function that will be run whenever the key sequence occurs
*/
void input_mapping_add( const wchar_t *sequence, const wchar_t *command );
void input_mapping_add(const wchar_t *sequence, const wchar_t *command);
/**
Insert all mapping names into the specified wcstring_list_t
*/
void input_mapping_get_names( wcstring_list_t &lst );
void input_mapping_get_names(wcstring_list_t &lst);
/**
Erase binding for specified key sequence
*/
bool input_mapping_erase( const wchar_t *sequence );
bool input_mapping_erase(const wchar_t *sequence);
/**
Gets the command bound to the specified key sequence. Returns true if it exists, false if not.
*/
bool input_mapping_get( const wcstring &sequence, wcstring &cmd );
bool input_mapping_get(const wcstring &sequence, wcstring &cmd);
/**
Return the sequence for the terminfo variable of the specified name.
@ -119,20 +119,20 @@ bool input_mapping_get( const wcstring &sequence, wcstring &cmd );
If no terminfo variable of the specified name could be found, return 0 and set errno to ENOENT.
If the terminfo variable does not have a value, return 0 and set errno to EILSEQ.
*/
const wchar_t *input_terminfo_get_sequence( const wchar_t *name );
const wchar_t *input_terminfo_get_sequence(const wchar_t *name);
/** Return the name of the terminfo variable with the specified sequence */
bool input_terminfo_get_name( const wcstring &seq, wcstring &name );
bool input_terminfo_get_name(const wcstring &seq, wcstring &name);
/** Return a list of all known terminfo names */
wcstring_list_t input_terminfo_get_names( bool skip_null );
wcstring_list_t input_terminfo_get_names(bool skip_null);
/** Returns the input function code for the given input function name. */
wchar_t input_function_get_code( const wcstring &name );
wchar_t input_function_get_code(const wcstring &name);
/** Returns a list of all existing input function names */
wcstring_list_t input_function_get_names( void );
wcstring_list_t input_function_get_names(void);
/** Updates our idea of whether we support term256 */
void update_fish_term256();

View file

@ -51,9 +51,9 @@ static int (*interrupt_handler)();
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))
@ -73,192 +73,193 @@ void input_common_destroy()
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. */
unsigned char arr[1];
bool do_loop;
unsigned char arr[1];
bool do_loop;
do
{
do
{
/* Invoke any poll handler */
if (poll_handler)
poll_handler();
fd_set fdset;
int fd_max=0;
int ioport = iothread_port();
int res;
fd_set fdset;
int fd_max=0;
int ioport = iothread_port();
int res;
FD_ZERO( &fdset );
FD_SET( 0, &fdset );
if( env_universal_server.fd > 0 )
{
FD_SET( env_universal_server.fd, &fdset );
if (fd_max < env_universal_server.fd) fd_max = env_universal_server.fd;
}
if (ioport > 0) {
FD_SET( ioport, &fdset );
if (fd_max < ioport) fd_max = ioport;
}
res = select( fd_max + 1, &fdset, 0, 0, 0 );
if( res==-1 )
{
switch( errno )
{
case EINTR:
case EAGAIN:
FD_ZERO(&fdset);
FD_SET(0, &fdset);
if (env_universal_server.fd > 0)
{
if( interrupt_handler )
{
int res = interrupt_handler();
if( res )
{
return res;
}
if( lookahead_count )
{
return lookahead_arr[--lookahead_count];
}
}
do_loop = true;
break;
FD_SET(env_universal_server.fd, &fdset);
if (fd_max < env_universal_server.fd) fd_max = env_universal_server.fd;
}
default:
if (ioport > 0)
{
/*
The terminal has been closed. Save and exit.
*/
return R_EOF;
FD_SET(ioport, &fdset);
if (fd_max < ioport) fd_max = ioport;
}
}
}
else
{
res = select(fd_max + 1, &fdset, 0, 0, 0);
if (res==-1)
{
switch (errno)
{
case EINTR:
case EAGAIN:
{
if (interrupt_handler)
{
int res = interrupt_handler();
if (res)
{
return res;
}
if (lookahead_count)
{
return lookahead_arr[--lookahead_count];
}
}
do_loop = true;
break;
}
default:
{
/*
The terminal has been closed. Save and exit.
*/
return R_EOF;
}
}
}
else
{
/* Assume we loop unless we see a character in stdin */
do_loop = true;
if( env_universal_server.fd > 0 && FD_ISSET( env_universal_server.fd, &fdset ) )
if (env_universal_server.fd > 0 && FD_ISSET(env_universal_server.fd, &fdset))
{
debug( 3, L"Wake up on universal variable event" );
debug(3, L"Wake up on universal variable event");
env_universal_read_all();
if( lookahead_count )
if (lookahead_count)
{
return lookahead_arr[--lookahead_count];
}
}
if ( ioport > 0 && FD_ISSET(ioport, &fdset))
{
if (ioport > 0 && FD_ISSET(ioport, &fdset))
{
iothread_service_completion();
if( lookahead_count )
if (lookahead_count)
{
return lookahead_arr[--lookahead_count];
}
}
}
if( FD_ISSET( STDIN_FILENO, &fdset ) )
{
if( read_blocked( 0, arr, 1 ) != 1 )
{
/* The teminal has been closed. Save and exit. */
return R_EOF;
}
if (FD_ISSET(STDIN_FILENO, &fdset))
{
if (read_blocked(0, arr, 1) != 1)
{
/* The teminal has been closed. Save and exit. */
return R_EOF;
}
/* We read from stdin, so don't loop */
do_loop = false;
}
}
}
while( do_loop );
return arr[0];
}
wchar_t input_common_readch( int timed )
{
if( lookahead_count == 0 )
{
if( timed )
{
int count;
fd_set fds;
struct timeval tm=
{
0,
1000 * WAIT_ON_ESCAPE
do_loop = false;
}
}
;
FD_ZERO( &fds );
FD_SET( 0, &fds );
count = select(1, &fds, 0, 0, &tm);
switch( count )
{
case 0:
return WEOF;
case -1:
return WEOF;
break;
default:
break;
}
}
while (do_loop);
wchar_t res;
static mbstate_t state;
while(1)
{
wint_t b = readb();
char bb;
size_t sz;
if( (b >= R_NULL) && (b < R_NULL + 1000) )
return b;
bb=b;
sz = mbrtowc( &res, &bb, 1, &state );
switch( sz )
{
case (size_t)(-1):
memset (&state, '\0', sizeof (state));
debug( 2, L"Illegal input" );
return R_NULL;
case (size_t)(-2):
break;
case 0:
return 0;
default:
return res;
}
}
}
else
{
if( !timed )
{
while( (lookahead_count >= 0) && (lookahead_arr[lookahead_count-1] == WEOF) )
lookahead_count--;
if( lookahead_count == 0 )
return input_common_readch(0);
}
return lookahead_arr[--lookahead_count];
}
return arr[0];
}
void input_common_unreadch( wint_t ch )
wchar_t input_common_readch(int timed)
{
lookahead_arr[lookahead_count++] = ch;
if (lookahead_count == 0)
{
if (timed)
{
int count;
fd_set fds;
struct timeval tm=
{
0,
1000 * WAIT_ON_ESCAPE
}
;
FD_ZERO(&fds);
FD_SET(0, &fds);
count = select(1, &fds, 0, 0, &tm);
switch (count)
{
case 0:
return WEOF;
case -1:
return WEOF;
break;
default:
break;
}
}
wchar_t res;
static mbstate_t state;
while (1)
{
wint_t b = readb();
char bb;
size_t sz;
if ((b >= R_NULL) && (b < R_NULL + 1000))
return b;
bb=b;
sz = mbrtowc(&res, &bb, 1, &state);
switch (sz)
{
case (size_t)(-1):
memset(&state, '\0', sizeof(state));
debug(2, L"Illegal input");
return R_NULL;
case (size_t)(-2):
break;
case 0:
return 0;
default:
return res;
}
}
}
else
{
if (!timed)
{
while ((lookahead_count >= 0) && (lookahead_arr[lookahead_count-1] == WEOF))
lookahead_count--;
if (lookahead_count == 0)
return input_common_readch(0);
}
return lookahead_arr[--lookahead_count];
}
}
void input_common_unreadch(wint_t ch)
{
lookahead_arr[lookahead_count++] = ch;
}

View file

@ -15,20 +15,20 @@ Header file for the low level input library
enum
{
/**
R_NULL is sometimes returned by the input when a character was
requested but none could be delivered, or when an exception
happened.
*/
R_NULL = INPUT_COMMON_RESERVED,
R_EOF
/**
R_NULL is sometimes returned by the input when a character was
requested but none could be delivered, or when an exception
happened.
*/
R_NULL = INPUT_COMMON_RESERVED,
R_EOF
}
;
;
/**
Init the library
*/
void input_common_init( int (*ih)() );
void input_common_init(int (*ih)());
/* Sets a callback to be invoked every time a byte is read */
void input_common_set_poll_callback(void (*handler)(void));
@ -47,13 +47,13 @@ void input_common_destroy();
WAIT_ON_ESCAPE milliseconds for a character to be available for
reading before returning with the value WEOF.
*/
wchar_t input_common_readch( int timed );
wchar_t input_common_readch(int timed);
/**
Push a character or a readline function onto the stack of unread
characters that input_readch will return before actually reading from fd
0.
*/
void input_common_unreadch( wint_t ch );
void input_common_unreadch(wint_t ch);
#endif

View file

@ -21,9 +21,11 @@
#include "intern.h"
/** Comparison function for intern'd strings */
class string_table_compare_t {
public:
bool operator()(const wchar_t *a, const wchar_t *b) const {
class string_table_compare_t
{
public:
bool operator()(const wchar_t *a, const wchar_t *b) const
{
return wcscmp(a, b) < 0;
}
};
@ -43,10 +45,10 @@ static string_table_t string_table;
/** The lock to provide thread safety for intern'd strings */
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 )
return NULL;
if (!in)
return NULL;
// debug( 0, L"intern %ls", in );
scoped_lock lock(intern_lock);
@ -54,17 +56,23 @@ static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
#if USE_SET
string_table_t::const_iterator iter = string_table.find(in);
if (iter != string_table.end()) {
if (iter != string_table.end())
{
result = *iter;
} else {
}
else
{
result = dup ? wcsdup(in) : in;
string_table.insert(result);
}
#else
string_table_t::iterator iter = std::lower_bound(string_table.begin(), string_table.end(), in, string_table_compare_t());
if (iter != string_table.end() && wcscmp(*iter, in) == 0) {
if (iter != string_table.end() && wcscmp(*iter, in) == 0)
{
result = *iter;
} else {
}
else
{
result = dup ? wcsdup(in) : in;
string_table.insert(iter, result);
}
@ -72,13 +80,13 @@ static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
return result;
}
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);
}

View file

@ -14,7 +14,7 @@
\param in the string to return an interned copy of
*/
const wchar_t *intern( const wchar_t *in );
const wchar_t *intern(const wchar_t *in);
/**
Insert the specified string literal into the pool of unique
@ -23,6 +23,6 @@ const wchar_t *intern( const wchar_t *in );
\param in the string to add to the interned pool
*/
const wchar_t *intern_static( const wchar_t *in );
const wchar_t *intern_static(const wchar_t *in);
#endif

193
io.cpp
View file

@ -51,78 +51,78 @@ Utilities for io redirection.
#include "io.h"
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( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
if (d->io_mode == IO_BUFFER)
{
wperror( L"fcntl" );
return;
} */
debug( 4, L"io_buffer_read: blocking read on fd %d", d->param1.pipe_fd[0] );
while(1)
{
char b[4096];
long l;
l=read_blocked( d->param1.pipe_fd[0], b, 4096 );
if( l==0 )
{
break;
}
else if( l<0 )
{
/*
exec_read_io_buffer is only called on jobs that have
exited, and will therefore never block. But a broken
pipe seems to cause some flags to reset, causing the
EOF flag to not be set. Therefore, EAGAIN is ignored
and we exit anyway.
*/
if( errno != EAGAIN )
/* if( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
{
wperror( L"fcntl" );
return;
} */
debug(4, L"io_buffer_read: blocking read on fd %d", d->param1.pipe_fd[0]);
while (1)
{
debug( 1,
_(L"An error occured while reading output from code block on file descriptor %d"),
d->param1.pipe_fd[0] );
wperror( L"io_buffer_read" );
}
char b[4096];
long l;
l=read_blocked(d->param1.pipe_fd[0], b, 4096);
if (l==0)
{
break;
}
else if (l<0)
{
/*
exec_read_io_buffer is only called on jobs that have
exited, and will therefore never block. But a broken
pipe seems to cause some flags to reset, causing the
EOF flag to not be set. Therefore, EAGAIN is ignored
and we exit anyway.
*/
if (errno != EAGAIN)
{
debug(1,
_(L"An error occured while reading output from code block on file descriptor %d"),
d->param1.pipe_fd[0]);
wperror(L"io_buffer_read");
}
break;
}
else
{
d->out_buffer_append( b, l );
}
break;
}
else
{
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;
io_data_t *buffer_redirect = new io_data_t;
buffer_redirect->out_buffer_create();
buffer_redirect->io_mode = IO_BUFFER;
buffer_redirect->is_input = is_input ? true : false;
buffer_redirect->fd=is_input?0:1;
io_data_t *buffer_redirect = new io_data_t;
buffer_redirect->out_buffer_create();
buffer_redirect->io_mode = IO_BUFFER;
buffer_redirect->is_input = is_input ? true : false;
buffer_redirect->fd=is_input?0:1;
if( exec_pipe( buffer_redirect->param1.pipe_fd ) == -1 )
{
debug( 1, PIPE_ERROR );
wperror (L"pipe");
success = false;
}
else if( fcntl( buffer_redirect->param1.pipe_fd[0],
F_SETFL,
O_NONBLOCK ) )
{
debug( 1, PIPE_ERROR );
wperror( L"fcntl" );
success = false;
}
if (exec_pipe(buffer_redirect->param1.pipe_fd) == -1)
{
debug(1, PIPE_ERROR);
wperror(L"pipe");
success = false;
}
else if (fcntl(buffer_redirect->param1.pipe_fd[0],
F_SETFL,
O_NONBLOCK))
{
debug(1, PIPE_ERROR);
wperror(L"fcntl");
success = false;
}
if (! success)
{
@ -130,28 +130,28 @@ io_data_t *io_buffer_create( bool is_input )
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
been called, and we need to close the output fd as well.
*/
if( io_buffer->is_input )
{
exec_close(io_buffer->param1.pipe_fd[1] );
}
/**
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.
*/
if (io_buffer->is_input)
{
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
calling exec_read_io_buffer on the buffer
*/
delete io_buffer;
/*
Dont free fd for writing. This should already be free'd before
calling exec_read_io_buffer on the buffer
*/
delete io_buffer;
}
void io_chain_t::remove(const io_data_t *element)
@ -218,31 +218,32 @@ void io_print(const io_chain_t &chain)
}
fprintf(stderr, "Chain %p (%ld items):\n", &chain, (long)chain.size());
for (size_t i=0; i < chain.size(); i++) {
for (size_t i=0; i < chain.size(); i++)
{
const io_data_t *io = chain.at(i);
fprintf(stderr, "\t%lu: fd:%d, input:%s, ", (unsigned long)i, io->fd, io->is_input ? "yes" : "no");
switch (io->io_mode)
{
case IO_FILE:
fprintf(stderr, "file (%s)\n", io->filename_cstr);
break;
case IO_PIPE:
fprintf(stderr, "pipe {%d, %d}\n", io->param1.pipe_fd[0], io->param1.pipe_fd[1]);
break;
case IO_FD:
fprintf(stderr, "FD map %d -> %d\n", io->param1.old_fd, io->fd);
break;
case IO_BUFFER:
fprintf(stderr, "buffer %p (size %lu)\n", io->out_buffer_ptr(), io->out_buffer_size());
break;
case IO_CLOSE:
fprintf(stderr, "close %d\n", io->fd);
break;
case IO_FILE:
fprintf(stderr, "file (%s)\n", io->filename_cstr);
break;
case IO_PIPE:
fprintf(stderr, "pipe {%d, %d}\n", io->param1.pipe_fd[0], io->param1.pipe_fd[1]);
break;
case IO_FD:
fprintf(stderr, "FD map %d -> %d\n", io->param1.old_fd, io->fd);
break;
case IO_BUFFER:
fprintf(stderr, "buffer %p (size %lu)\n", io->out_buffer_ptr(), io->out_buffer_size());
break;
case IO_CLOSE:
fprintf(stderr, "close %d\n", io->fd);
break;
}
}
}
void io_duplicate_prepend( const io_chain_t &src, io_chain_t &dst )
void io_duplicate_prepend(const io_chain_t &src, io_chain_t &dst)
{
return dst.duplicate_prepend(src);
}
@ -259,7 +260,8 @@ const io_data_t *io_chain_t::get_io_for_fd(int fd) const
while (idx--)
{
const io_data_t *data = this->at(idx);
if (data->fd == fd) {
if (data->fd == fd)
{
return data;
}
}
@ -272,7 +274,8 @@ io_data_t *io_chain_t::get_io_for_fd(int fd)
while (idx--)
{
io_data_t *data = this->at(idx);
if (data->fd == fd) {
if (data->fd == fd)
{
return data;
}
}

84
io.h
View file

@ -10,7 +10,7 @@ using std::tr1::shared_ptr;
*/
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 */
@ -24,71 +24,77 @@ private:
void operator=(const io_data_t &rhs);
public:
/** Type of redirect */
int io_mode;
/** FD to redirect */
int fd;
/** Type of redirect */
int io_mode;
/** FD to redirect */
int fd;
/**
Type-specific parameter for redirection
*/
union
{
/** Fds for IO_PIPE and for IO_BUFFER */
int pipe_fd[2];
/** fd to redirect specified fd to, for IO_FD */
int old_fd;
} param1;
/**
Type-specific parameter for redirection
*/
union
{
/** Fds for IO_PIPE and for IO_BUFFER */
int pipe_fd[2];
/** fd to redirect specified fd to, for IO_FD */
int old_fd;
} param1;
/** Second type-specific paramter for redirection */
union
{
/** file creation flags to send to open for IO_FILE */
int flags;
/** Whether to close old_fd for IO_FD */
int close_old;
} param2;
/** Second type-specific paramter for redirection */
union
{
/** file creation flags to send to open for IO_FILE */
int flags;
/** Whether to close old_fd for IO_FD */
int close_old;
} param2;
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
const char *filename_cstr;
/** Convenience to set filename_cstr via wcstring */
void set_filename(const wcstring &str) {
void set_filename(const wcstring &str)
{
free((void *)filename_cstr);
filename_cstr = wcs2str(str.c_str());
}
/** Function to create the output buffer */
void out_buffer_create() {
void out_buffer_create()
{
out_buffer.reset(new std::vector<char>);
}
/** Function to append to the buffer */
void out_buffer_append(const char *ptr, size_t count) {
void out_buffer_append(const char *ptr, size_t count)
{
assert(out_buffer.get() != NULL);
out_buffer->insert(out_buffer->end(), ptr, ptr + count);
}
/** Function to get a pointer to the buffer */
char *out_buffer_ptr(void) {
char *out_buffer_ptr(void)
{
assert(out_buffer.get() != NULL);
return out_buffer->empty() ? NULL : &out_buffer->at(0);
}
const char *out_buffer_ptr(void) const {
const char *out_buffer_ptr(void) const
{
assert(out_buffer.get() != NULL);
return out_buffer->empty() ? NULL : &out_buffer->at(0);
}
/** Function to get the size of the buffer */
size_t out_buffer_size(void) const {
size_t out_buffer_size(void) const
{
assert(out_buffer.get() != NULL);
return out_buffer->size();
}
/** Set to true if this is an input io redirection */
bool is_input;
/** Set to true if this is an input io redirection */
bool is_input;
io_data_t() :
out_buffer(),
@ -112,12 +118,14 @@ public:
{
}
~io_data_t() {
~io_data_t()
{
free((void *)filename_cstr);
}
};
class io_chain_t : public std::vector<io_data_t *> {
class io_chain_t : public std::vector<io_data_t *>
{
public:
io_chain_t();
io_chain_t(io_data_t *);
@ -144,7 +152,7 @@ io_chain_t io_duplicate(const io_chain_t &chain);
io_chain_t io_unique(const io_chain_t &chain);
/** Prepends a copy of the specified 'src' chain of redirections to 'dst.' Uses operator new. */
void io_duplicate_prepend( const io_chain_t &src, io_chain_t &dst );
void io_duplicate_prepend(const io_chain_t &src, io_chain_t &dst);
/** Destroys an io_chain */
void io_chain_destroy(io_chain_t &chain);
@ -159,7 +167,7 @@ io_data_t *io_chain_get(io_chain_t &src, int fd);
/**
Free all resources used by a IO_BUFFER type io redirection.
*/
void io_buffer_destroy( io_data_t *io_buffer );
void io_buffer_destroy(io_data_t *io_buffer);
/**
Create a IO_BUFFER type io redirection, complete with a pipe and a
@ -170,14 +178,14 @@ void io_buffer_destroy( io_data_t *io_buffer );
used to buffer the output of a command, or non-zero to buffer the
input to a command.
*/
io_data_t *io_buffer_create( bool is_input );
io_data_t *io_buffer_create(bool is_input);
/**
Close output pipe, and read from input pipe until eof.
*/
void io_buffer_read( io_data_t *d );
void io_buffer_read(io_data_t *d);
/** Print debug information about the specified IO redirection chain to stderr. */
void io_print( const io_chain_t &chain );
void io_print(const io_chain_t &chain);
#endif

View file

@ -13,38 +13,42 @@
#include <queue>
#ifdef _POSIX_THREAD_THREADS_MAX
#if _POSIX_THREAD_THREADS_MAX < 64
#define IO_MAX_THREADS _POSIX_THREAD_THREADS_MAX
#endif
#if _POSIX_THREAD_THREADS_MAX < 64
#define IO_MAX_THREADS _POSIX_THREAD_THREADS_MAX
#endif
#endif
#ifndef IO_MAX_THREADS
#define IO_MAX_THREADS 64
#define IO_MAX_THREADS 64
#endif
static int s_active_thread_count;
typedef unsigned char ThreadIndex_t;
static struct WorkerThread_t {
ThreadIndex_t idx;
pthread_t thread;
static struct WorkerThread_t
{
ThreadIndex_t idx;
pthread_t thread;
} threads[IO_MAX_THREADS];
struct ThreadedRequest_t {
int sequenceNumber;
struct ThreadedRequest_t
{
int sequenceNumber;
int (*handler)(void *);
void (*completionCallback)(void *, int);
void *context;
int handlerResult;
int (*handler)(void *);
void (*completionCallback)(void *, int);
void *context;
int handlerResult;
};
static struct WorkerThread_t *next_vacant_thread_slot(void) {
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
if (! threads[i].thread) return &threads[i];
}
return NULL;
static struct WorkerThread_t *next_vacant_thread_slot(void)
{
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++)
{
if (! threads[i].thread) return &threads[i];
}
return NULL;
}
static pthread_mutex_t s_request_queue_lock;
@ -52,40 +56,46 @@ static std::queue<ThreadedRequest_t *> s_request_queue;
static int s_last_sequence_number;
static int s_read_pipe, s_write_pipe;
static void iothread_init(void) {
static bool inited = false;
if (! inited) {
inited = true;
static void iothread_init(void)
{
static bool inited = false;
if (! inited)
{
inited = true;
/* Initialize the queue lock */
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL));
/* Initialize the queue lock */
VOMIT_ON_FAILURE(pthread_mutex_init(&s_request_queue_lock, NULL));
/* Initialize the completion pipes */
int pipes[2] = {0, 0};
VOMIT_ON_FAILURE(pipe(pipes));
s_read_pipe = pipes[0];
s_write_pipe = pipes[1];
/* Initialize the completion pipes */
int pipes[2] = {0, 0};
VOMIT_ON_FAILURE(pipe(pipes));
s_read_pipe = pipes[0];
s_write_pipe = pipes[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_write_pipe, F_SETFD, FD_CLOEXEC));
/* Tell each thread its index */
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++) {
threads[i].idx = i;
/* Tell each thread its index */
for (ThreadIndex_t i=0; i < IO_MAX_THREADS; i++)
{
threads[i].idx = i;
}
}
}
}
static void add_to_queue(struct ThreadedRequest_t *req) {
ASSERT_IS_LOCKED(s_request_queue_lock);
static void add_to_queue(struct ThreadedRequest_t *req)
{
ASSERT_IS_LOCKED(s_request_queue_lock);
s_request_queue.push(req);
}
static ThreadedRequest_t *dequeue_request(void) {
static ThreadedRequest_t *dequeue_request(void)
{
ThreadedRequest_t *result = NULL;
scoped_lock lock(s_request_queue_lock);
if (! s_request_queue.empty()) {
if (! s_request_queue.empty())
{
result = s_request_queue.front();
s_request_queue.pop();
}
@ -93,68 +103,76 @@ static ThreadedRequest_t *dequeue_request(void) {
}
/* The function that does thread work. */
static void *iothread_worker(void *threadPtr) {
assert(threadPtr != NULL);
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
static void *iothread_worker(void *threadPtr)
{
assert(threadPtr != NULL);
struct WorkerThread_t *thread = (struct WorkerThread_t *)threadPtr;
/* Grab a request off of the queue */
struct ThreadedRequest_t *req = dequeue_request();
/* Grab a request off of the queue */
struct ThreadedRequest_t *req = dequeue_request();
/* Run the handler and store the result */
if (req) {
req->handlerResult = req->handler(req->context);
}
/* Run the handler and store the result */
if (req)
{
req->handlerResult = req->handler(req->context);
}
/* Write our index to wake up the main thread */
VOMIT_ON_FAILURE(! write_loop(s_write_pipe, (const char *)&thread->idx, sizeof thread->idx));
/* Write our index to wake up the main thread */
VOMIT_ON_FAILURE(! write_loop(s_write_pipe, (const char *)&thread->idx, sizeof thread->idx));
/* We're done */
return req;
/* We're done */
return req;
}
/* 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);
if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS) {
struct WorkerThread_t *thread = next_vacant_thread_slot();
assert(thread != NULL);
if (! s_request_queue.empty() && s_active_thread_count < IO_MAX_THREADS)
{
struct WorkerThread_t *thread = next_vacant_thread_slot();
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. */
sigset_t newSet, savedSet;
sigfillset(&newSet);
VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &newSet, &savedSet));
/* Spawn a thread. */
int err;
do {
err = 0;
if (pthread_create(&thread->thread, NULL, iothread_worker, thread)) {
err = errno;
}
} while (err == EAGAIN);
/* Spawn a thread. */
int err;
do
{
err = 0;
if (pthread_create(&thread->thread, NULL, iothread_worker, thread))
{
err = errno;
}
}
while (err == EAGAIN);
/* Need better error handling - perhaps try again later. */
assert(err == 0);
assert(err == 0);
/* Note that we are spawned another thread */
s_active_thread_count += 1;
/* Note that we are spawned another thread */
s_active_thread_count += 1;
/* Restore our sigmask */
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_NOT_FORKED_CHILD();
iothread_init();
iothread_init();
/* Create and initialize a request. */
struct ThreadedRequest_t *req = new ThreadedRequest_t();
req->handler = handler;
req->completionCallback = completionCallback;
req->context = context;
req->sequenceNumber = ++s_last_sequence_number;
/* Create and initialize a request. */
struct ThreadedRequest_t *req = new ThreadedRequest_t();
req->handler = handler;
req->completionCallback = completionCallback;
req->context = context;
req->sequenceNumber = ++s_last_sequence_number;
/* Take our lock */
scoped_lock lock(s_request_queue_lock);
@ -167,42 +185,46 @@ int iothread_perform_base(int (*handler)(void *), void (*completionCallback)(voi
return 0;
}
int iothread_port(void) {
iothread_init();
return s_read_pipe;
int iothread_port(void)
{
iothread_init();
return s_read_pipe;
}
void iothread_service_completion(void) {
void iothread_service_completion(void)
{
ASSERT_IS_MAIN_THREAD();
ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
assert(threadIdx < IO_MAX_THREADS);
ThreadIndex_t threadIdx = (ThreadIndex_t)-1;
VOMIT_ON_FAILURE(1 != read_loop(iothread_port(), &threadIdx, sizeof threadIdx));
assert(threadIdx < IO_MAX_THREADS);
struct WorkerThread_t *thread = &threads[threadIdx];
assert(thread->thread != 0);
struct WorkerThread_t *thread = &threads[threadIdx];
assert(thread->thread != 0);
struct ThreadedRequest_t *req = NULL;
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
struct ThreadedRequest_t *req = NULL;
VOMIT_ON_FAILURE(pthread_join(thread->thread, (void **)&req));
/* Free up this thread */
thread->thread = 0;
assert(s_active_thread_count > 0);
s_active_thread_count -= 1;
/* Free up this thread */
thread->thread = 0;
assert(s_active_thread_count > 0);
s_active_thread_count -= 1;
/* Handle the request */
if (req) {
/* Handle the request */
if (req)
{
if (req->completionCallback)
req->completionCallback(req->context, req->handlerResult);
delete req;
}
/* Maybe spawn another thread, if there's more work to be done. */
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock));
iothread_spawn_if_needed();
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock));
/* Maybe spawn another thread, if there's more work to be done. */
VOMIT_ON_FAILURE(pthread_mutex_lock(&s_request_queue_lock));
iothread_spawn_if_needed();
VOMIT_ON_FAILURE(pthread_mutex_unlock(&s_request_queue_lock));
}
void iothread_drain_all(void) {
void iothread_drain_all(void)
{
ASSERT_IS_MAIN_THREAD();
ASSERT_IS_NOT_FORKED_CHILD();
if (s_active_thread_count == 0)
@ -212,7 +234,8 @@ void iothread_drain_all(void) {
int thread_count = s_active_thread_count;
double now = timef();
#endif
while (s_active_thread_count > 0) {
while (s_active_thread_count > 0)
{
iothread_service_completion();
}
#if TIME_DRAIN

View file

@ -30,7 +30,8 @@ void iothread_drain_all(void);
/** Helper template */
template<typename T>
int iothread_perform(int (*handler)(T *), void (*completionCallback)(T *, int), T *context) {
int iothread_perform(int (*handler)(T *), void (*completionCallback)(T *, int), T *context)
{
return iothread_perform_base((int (*)(void *))handler, (void (*)(void *, int))completionCallback, static_cast<void *>(context));
}

View file

@ -20,78 +20,78 @@
#include "input_common.h"
int writestr( char *str )
int writestr(char *str)
{
write( 1, str, strlen(str) );
return 0;
write(1, str, strlen(str));
return 0;
}
int main( int argc, char **argv)
int main(int argc, char **argv)
{
set_main_thread();
set_main_thread();
setup_fork_guards();
setlocale( LC_ALL, "" );
setlocale(LC_ALL, "");
if( argc == 2 )
{
static char term_buffer[2048];
char *termtype = getenv ("TERM");
char *tbuff = new char[9999];
char *res;
tgetent( term_buffer, termtype );
res = tgetstr( argv[1], &tbuff );
if( res != 0 )
if (argc == 2)
{
while( *res != 0 )
{
printf("%d ", *res );
static char term_buffer[2048];
char *termtype = getenv("TERM");
char *tbuff = new char[9999];
char *res;
tgetent(term_buffer, termtype);
res = tgetstr(argv[1], &tbuff);
if (res != 0)
{
while (*res != 0)
{
printf("%d ", *res);
res++;
}
printf( "\n" );
res++;
}
printf("\n");
}
else
{
printf("Undefined sequence\n");
}
}
else
{
printf("Undefined sequence\n");
}
}
else
{
char scratch[1024];
unsigned int c;
char scratch[1024];
unsigned int c;
struct termios modes, /* so we can change the modes */
savemodes; /* so we can reset the modes when we're done */
struct termios modes, /* so we can change the modes */
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 */
savemodes = modes; /* save a copy so we can reset them */
tcgetattr(0,&modes); /* get the current terminal modes */
savemodes = modes; /* save a copy so we can reset them */
modes.c_lflag &= ~ICANON; /* turn off canonical mode */
modes.c_lflag &= ~ECHO; /* turn off echo mode */
modes.c_cc[VMIN]=1;
modes.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&modes); /* set the new modes */
while(1)
modes.c_lflag &= ~ICANON; /* turn off canonical mode */
modes.c_lflag &= ~ECHO; /* turn off echo mode */
modes.c_cc[VMIN]=1;
modes.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&modes); /* set the new modes */
while (1)
{
if( (c=input_common_readch(0)) == EOF )
break;
if( (c > 31) && (c != 127) )
sprintf( scratch, "dec: %d hex: %x char: %c\n", c, c, c );
else
sprintf( scratch, "dec: %d hex: %x\n", c, c );
writestr( scratch );
if ((c=input_common_readch(0)) == EOF)
break;
if ((c > 31) && (c != 127))
sprintf(scratch, "dec: %d hex: %x char: %c\n", c, c, c);
else
sprintf(scratch, "dec: %d hex: %x\n", c, c);
writestr(scratch);
}
/* reset the terminal to the saved mode */
tcsetattr(0,TCSANOW,&savemodes);
input_common_destroy();
}
/* reset the terminal to the saved mode */
tcsetattr(0,TCSANOW,&savemodes);
input_common_destroy();
}
return 0;
return 0;
}

160
kill.cpp
View file

@ -36,7 +36,7 @@
*/
#define KILL_MAX 8192
/** Last kill string */
/** Last kill string */
//static ll_node_t *kill_last=0;
/** Current kill string */
@ -57,76 +57,78 @@ static wchar_t *cut_buffer=0;
*/
static int has_xsel()
{
static int res=-1;
if (res < 0) {
res = !! path_get_path(L"xsel", NULL);
static int res=-1;
if (res < 0)
{
res = !! path_get_path(L"xsel", NULL);
}
return res;
return res;
}
void kill_add( const wcstring &str )
void kill_add(const wcstring &str)
{
ASSERT_IS_MAIN_THREAD();
if (str.empty())
return;
wcstring cmd;
wcstring cmd;
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,
and, if so, use it instead of checking the display, etc.
/*
Check to see if user has set the FISH_CLIPBOARD_CMD variable,
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
command too, so, the command used must accept the input via stdin.
*/
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.
*/
const env_var_t clipboard_wstr = env_get_string(L"FISH_CLIPBOARD_CMD");
if( !clipboard_wstr.missing() )
{
escaped_str = escape( str.c_str(), 1 );
const env_var_t clipboard_wstr = env_get_string(L"FISH_CLIPBOARD_CMD");
if (!clipboard_wstr.missing())
{
escaped_str = escape(str.c_str(), 1);
cmd.assign(L"echo -n ");
cmd.append(escaped_str);
cmd.append(clipboard_wstr);
}
else
{
/* This is for sending the kill to the X copy-and-paste buffer */
if( !has_xsel() ) {
return;
}
else
{
/* This is for sending the kill to the X copy-and-paste buffer */
if (!has_xsel())
{
return;
}
const env_var_t disp_wstr = env_get_string( L"DISPLAY" );
if( !disp_wstr.missing() )
{
escaped_str = escape( str.c_str(), 1 );
const env_var_t disp_wstr = env_get_string(L"DISPLAY");
if (!disp_wstr.missing())
{
escaped_str = escape(str.c_str(), 1);
cmd.assign(L"echo ");
cmd.append(escaped_str);
cmd.append(L"|xsel -b" );
cmd.append(L"|xsel -b");
}
}
}
if (! cmd.empty())
{
if( exec_subshell(cmd) == -1 )
if (! cmd.empty())
{
/*
Do nothing on failiure
*/
if (exec_subshell(cmd) == -1)
{
/*
Do nothing on failiure
*/
}
free(cut_buffer);
cut_buffer = escaped_str;
}
free( cut_buffer );
cut_buffer = escaped_str;
}
}
/**
Remove first match for specified string from circular list
*/
static void kill_remove( const wcstring &s )
static void kill_remove(const wcstring &s)
{
ASSERT_IS_MAIN_THREAD();
kill_list_t::iterator iter = std::find(kill_list.begin(), kill_list.end(), s);
@ -136,19 +138,22 @@ 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_add( newv );
kill_remove(old);
kill_add(newv);
}
const wchar_t *kill_yank_rotate()
{
ASSERT_IS_MAIN_THREAD();
// Move the first element to the end
if (kill_list.empty()) {
if (kill_list.empty())
{
return NULL;
} else {
}
else
{
kill_list.splice(kill_list.end(), kill_list, kill_list.begin());
return kill_list.front().c_str();
}
@ -160,52 +165,55 @@ const wchar_t *kill_yank_rotate()
*/
static void kill_check_x_buffer()
{
if( !has_xsel() )
return;
if (!has_xsel())
return;
const env_var_t disp = env_get_string(L"DISPLAY");
if( ! disp.missing())
{
size_t i;
wcstring cmd = L"xsel -t 500 -b";
wcstring new_cut_buffer=L"";
wcstring_list_t list;
if( exec_subshell( cmd, list ) != -1 )
const env_var_t disp = env_get_string(L"DISPLAY");
if (! disp.missing())
{
size_t i;
wcstring cmd = L"xsel -t 500 -b";
wcstring new_cut_buffer=L"";
wcstring_list_t list;
if (exec_subshell(cmd, list) != -1)
{
for( i=0; i<list.size(); i++ )
{
wcstring next_line = escape_string( list.at(i), 0 );
for (i=0; i<list.size(); i++)
{
wcstring next_line = escape_string(list.at(i), 0);
if (i > 0) new_cut_buffer += L"\\n";
new_cut_buffer += next_line;
}
}
if( new_cut_buffer.size() > 0 )
{
/*
The buffer is inserted with backslash escapes,
since we don't really like tabs, newlines,
etc. anyway.
*/
if (new_cut_buffer.size() > 0)
{
/*
The buffer is inserted with backslash escapes,
since we don't really like tabs, newlines,
etc. anyway.
*/
if (cut_buffer == NULL || cut_buffer != new_cut_buffer)
{
free(cut_buffer);
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()
{
kill_check_x_buffer();
if (kill_list.empty()) {
kill_check_x_buffer();
if (kill_list.empty())
{
return L"";
} else {
}
else
{
return kill_list.front().c_str();
}
}
@ -220,7 +228,7 @@ void kill_init()
void kill_destroy()
{
if( cut_buffer )
free( cut_buffer );
if (cut_buffer)
free(cut_buffer);
}

4
kill.h
View file

@ -12,11 +12,11 @@
/**
Replace the specified string in the killring
*/
void kill_replace( const wcstring &old, const wcstring &newv );
void kill_replace(const wcstring &old, const wcstring &newv);
/** Add a string to the top of the killring */
void kill_add( const wcstring &str );
void kill_add(const wcstring &str);
/** Rotate the killring */
const wchar_t *kill_yank_rotate();

101
lru.h
View file

@ -13,12 +13,17 @@
#include "common.h"
/** A predicate to compare dereferenced pointers */
struct dereference_less_t {
struct dereference_less_t
{
template <typename ptr_t>
bool operator()(ptr_t p1, ptr_t p2) const { return *p1 < *p2; }
bool operator()(ptr_t p1, ptr_t p2) const
{
return *p1 < *p2;
}
};
class lru_node_t {
class lru_node_t
{
template<class T> friend class lru_cache_t;
/** Our linked list pointer */
@ -32,12 +37,16 @@ public:
lru_node_t(const wcstring &pkey) : prev(NULL), next(NULL), key(pkey) { }
/** operator< for std::set */
bool operator<(const lru_node_t &other) const { return key < other.key; }
bool operator<(const lru_node_t &other) const
{
return key < other.key;
}
};
template<class node_type_t>
class lru_cache_t {
private:
class lru_cache_t
{
private:
/** Max node count */
const size_t max_node_count;
@ -49,7 +58,8 @@ class lru_cache_t {
typedef std::set<lru_node_t *, dereference_less_t> node_set_t;
node_set_t node_set;
void promote_node(node_type_t *node) {
void promote_node(node_type_t *node)
{
/* We should never promote the mouth */
assert(node != &mouth);
@ -64,7 +74,8 @@ class lru_cache_t {
mouth.next = node;
}
void evict_node(node_type_t *condemned_node) {
void evict_node(node_type_t *condemned_node)
{
/* We should never evict the mouth */
assert(condemned_node != NULL && condemned_node != &mouth);
@ -80,12 +91,13 @@ class lru_cache_t {
this->node_was_evicted(condemned_node);
}
void evict_last_node(void) {
void evict_last_node(void)
{
/* Simple */
evict_node((node_type_t *)mouth.prev);
}
protected:
protected:
/** Head of the linked list */
lru_node_t mouth;
@ -93,10 +105,11 @@ class lru_cache_t {
/** Overridable callback for when a node is evicted */
virtual void node_was_evicted(node_type_t *node) { }
public:
public:
/** Constructor */
lru_cache_t(size_t max_size = 1024 ) : max_node_count(max_size), node_count(0), mouth(wcstring()) {
lru_cache_t(size_t max_size = 1024) : max_node_count(max_size), node_count(0), mouth(wcstring())
{
/* Hook up the mouth to itself: a one node circularly linked list! */
mouth.prev = mouth.next = &mouth;
}
@ -106,7 +119,8 @@ class lru_cache_t {
/** Returns the node for a given key, or NULL */
node_type_t *get_node(const wcstring &key) {
node_type_t *get_node(const wcstring &key)
{
node_type_t *result = NULL;
/* Construct a fake node as our key */
@ -116,7 +130,8 @@ class lru_cache_t {
node_set_t::iterator iter = node_set.find(&node_key);
/* If we found a node, promote and return it */
if (iter != node_set.end()) {
if (iter != node_set.end())
{
result = static_cast<node_type_t*>(*iter);
promote_node(result);
}
@ -124,7 +139,8 @@ class lru_cache_t {
}
/** Evicts the node for a given key, returning true if a node was evicted. */
bool evict_node(const wcstring &key) {
bool evict_node(const wcstring &key)
{
/* Construct a fake node as our key */
lru_node_t node_key(key);
@ -139,7 +155,8 @@ class lru_cache_t {
}
/** Adds a node under the given key. Returns true if the node was added, false if the node was not because a node with that key is already in the set. */
bool add_node(node_type_t *node) {
bool add_node(node_type_t *node)
{
/* Add our node without eviction */
if (! this->add_node_without_eviction(node))
return false;
@ -153,7 +170,8 @@ class lru_cache_t {
}
/** Adds a node under the given key without triggering eviction. Returns true if the node was added, false if the node was not because a node with that key is already in the set. */
bool add_node_without_eviction(node_type_t *node) {
bool add_node_without_eviction(node_type_t *node)
{
assert(node != NULL && node != &mouth);
/* Try inserting; return false if it was already in the set */
@ -178,31 +196,56 @@ class lru_cache_t {
}
/** Counts nodes */
size_t size(void) {
size_t size(void)
{
return node_count;
}
/** Evicts all nodes */
void evict_all_nodes(void) {
while (node_count > 0) {
void evict_all_nodes(void)
{
while (node_count > 0)
{
evict_last_node();
}
}
/** Iterator for walking nodes, from least recently used to most */
class iterator {
class iterator
{
lru_node_t *node;
public:
public:
iterator(lru_node_t *val) : node(val) { }
void operator++() { node = node->prev; }
void operator++(int x) { node = node->prev; }
bool operator==(const iterator &other) { return node == other.node; }
bool operator!=(const iterator &other) { return !(*this == other); }
node_type_t *operator*() { return static_cast<node_type_t *>(node); }
void operator++()
{
node = node->prev;
}
void operator++(int x)
{
node = node->prev;
}
bool operator==(const iterator &other)
{
return node == other.node;
}
bool operator!=(const iterator &other)
{
return !(*this == other);
}
node_type_t *operator*()
{
return static_cast<node_type_t *>(node);
}
};
iterator begin() { return iterator(mouth.prev); }
iterator end() { return iterator(&mouth); }
iterator begin()
{
return iterator(mouth.prev);
}
iterator end()
{
return iterator(&mouth);
}
};

1926
mimedb.cpp

File diff suppressed because it is too large Load diff

View file

@ -62,24 +62,24 @@
*/
#define COLORS (sizeof(col)/sizeof(wchar_t *))
static int writeb_internal( char c );
static int writeb_internal(char c);
/**
Names of different colors.
*/
static const wchar_t *col[]=
{
L"black",
L"red",
L"green",
L"brown",
L"yellow",
L"blue",
L"magenta",
L"purple",
L"cyan",
L"white"
L"normal"
L"black",
L"red",
L"green",
L"brown",
L"yellow",
L"blue",
L"magenta",
L"purple",
L"cyan",
L"white"
L"normal"
}
;
@ -91,17 +91,17 @@ static const wchar_t *col[]=
*/
static const int col_idx[]=
{
0,
1,
2,
3,
3,
4,
5,
5,
6,
7,
FISH_COLOR_NORMAL,
0,
1,
2,
3,
3,
4,
5,
5,
6,
7,
FISH_COLOR_NORMAL,
};
/**
@ -119,46 +119,57 @@ static wcstring current_term;
static bool support_term256 = false;
void output_set_writer( int (*writer)(char) )
void output_set_writer(int (*writer)(char))
{
CHECK( writer, );
out = writer;
CHECK(writer,);
out = writer;
}
int (*output_get_writer())(char)
{
return out;
return out;
}
static bool term256_support_is_native(void) {
static bool term256_support_is_native(void)
{
/* Return YES if we think the term256 support is "native" as opposed to forced. */
return max_colors == 256;
}
bool output_get_supports_term256() {
bool output_get_supports_term256()
{
return support_term256;
}
void output_set_supports_term256(bool val) {
void output_set_supports_term256(bool val)
{
support_term256 = val;
}
static unsigned char index_for_color(rgb_color_t c) {
if (c.is_named() || ! output_get_supports_term256()) {
static unsigned char index_for_color(rgb_color_t c)
{
if (c.is_named() || ! output_get_supports_term256())
{
return c.to_name_index();
} else {
}
else
{
return c.to_term256_index();
}
}
static bool write_color(char *todo, unsigned char idx, bool is_fg) {
static bool write_color(char *todo, unsigned char idx, bool is_fg)
{
bool result = false;
if (idx < 16 || term256_support_is_native()) {
if (idx < 16 || term256_support_is_native())
{
/* Use tparm */
writembs( tparm( todo, idx ) );
writembs(tparm(todo, idx));
result = true;
} else {
}
else
{
/* We are attempting to bypass the term here. Generate the ANSI escape sequence ourself. */
char stridx[128];
format_long_safe(stridx, idx);
@ -168,8 +179,10 @@ static bool write_color(char *todo, unsigned char idx, bool is_fg) {
strcat(buff, "m");
int (*writer)(char) = output_get_writer();
if (writer) {
for (size_t i=0; buff[i]; i++) {
if (writer)
{
for (size_t i=0; buff[i]; i++)
{
writer(buff[i]);
}
}
@ -179,22 +192,34 @@ static bool write_color(char *todo, unsigned char idx, bool is_fg) {
return result;
}
static bool write_foreground_color(unsigned char idx) {
if (set_a_foreground && set_a_foreground[0]) {
static bool write_foreground_color(unsigned char idx)
{
if (set_a_foreground && set_a_foreground[0])
{
return write_color(set_a_foreground, idx, true);
} else if (set_foreground && set_foreground[0]) {
}
else if (set_foreground && set_foreground[0])
{
return write_color(set_foreground, idx, true);
} else {
}
else
{
return false;
}
}
static bool write_background_color(unsigned char idx) {
if (set_a_background && set_a_background[0]) {
static bool write_background_color(unsigned char idx)
{
if (set_a_background && set_a_background[0])
{
return write_color(set_a_background, idx, false);
} else if (set_background && set_background[0]) {
}
else if (set_background && set_background[0])
{
return write_color(set_background, idx, false);
} else {
}
else
{
return false;
}
}
@ -212,383 +237,389 @@ void set_color(rgb_color_t c, rgb_color_t c2)
const rgb_color_t normal = 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 int was_bold=0;
static int was_underline=0;
int bg_set=0, last_bg_set=0;
static rgb_color_t last_color2 = rgb_color_t::normal();
static int was_bold=0;
static int was_underline=0;
int bg_set=0, last_bg_set=0;
int is_bold = 0;
int is_underline = 0;
int is_bold = 0;
int is_underline = 0;
/*
Test if we have at least basic support for setting fonts, colors
and related bits - otherwise just give up...
*/
if( !exit_attribute_mode )
{
return;
}
/*
Test if we have at least basic support for setting fonts, colors
and related bits - otherwise just give up...
*/
if (!exit_attribute_mode)
{
return;
}
is_bold |= c.is_bold();
is_bold |= c2.is_bold();
is_bold |= c.is_bold();
is_bold |= c2.is_bold();
is_underline |= c.is_underline();
is_underline |= c2.is_underline();
is_underline |= c.is_underline();
is_underline |= c2.is_underline();
if( c.is_reset() || c2.is_reset())
{
c = c2 = normal;
was_bold=0;
was_underline=0;
if (c.is_reset() || c2.is_reset())
{
c = c2 = normal;
was_bold=0;
was_underline=0;
/*
If we exit attibute mode, we must first set a color, or
previously coloured text might lose it's
color. Terminals are weird...
*/
write_foreground_color(0);
writembs( exit_attribute_mode );
return;
}
writembs(exit_attribute_mode);
return;
}
if( was_bold && !is_bold )
{
/*
Only way to exit bold mode is a reset of all attributes.
*/
writembs( exit_attribute_mode );
last_color = normal;
last_color2 = normal;
was_bold=0;
was_underline=0;
}
if (was_bold && !is_bold)
{
/*
Only way to exit bold mode is a reset of all attributes.
*/
writembs(exit_attribute_mode);
last_color = normal;
last_color2 = normal;
was_bold=0;
was_underline=0;
}
if( ! last_color2.is_normal() &&
! last_color2.is_reset() &&
! last_color2.is_ignore() )
{
/*
Background was set
*/
last_bg_set=1;
}
if (! last_color2.is_normal() &&
! last_color2.is_reset() &&
! last_color2.is_ignore())
{
/*
Background was set
*/
last_bg_set=1;
}
if( ! c2.is_normal() &&
! c2.is_ignore())
{
/*
Background is set
*/
bg_set=1;
if ( c==c2 )
if (! c2.is_normal() &&
! c2.is_ignore())
{
/*
Background is set
*/
bg_set=1;
if (c==c2)
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(bg_set && !last_bg_set)
{
/*
Background color changed and is set, so we enter bold
mode to make reading easier. This means bold mode is
_always_ on when the background color is set.
*/
writembs( enter_bold_mode );
}
if(!bg_set && last_bg_set)
{
/*
Background color changed and is no longer set, so we
exit bold mode
*/
writembs( exit_attribute_mode );
was_bold=0;
was_underline=0;
/*
We don't know if exit_attribute_mode resets colors, so
we set it to something known.
*/
if( write_foreground_color(0))
{
last_color=rgb_color_t::black();
}
}
}
if( last_color != c )
{
if( c.is_normal() )
if ((enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0))
{
write_foreground_color(0);
writembs( exit_attribute_mode );
last_color2 = rgb_color_t::normal();
was_bold=0;
was_underline=0;
if (bg_set && !last_bg_set)
{
/*
Background color changed and is set, so we enter bold
mode to make reading easier. This means bold mode is
_always_ on when the background color is set.
*/
writembs(enter_bold_mode);
}
if (!bg_set && last_bg_set)
{
/*
Background color changed and is no longer set, so we
exit bold mode
*/
writembs(exit_attribute_mode);
was_bold=0;
was_underline=0;
/*
We don't know if exit_attribute_mode resets colors, so
we set it to something known.
*/
if (write_foreground_color(0))
{
last_color=rgb_color_t::black();
}
}
}
else if( ! c.is_special() )
if (last_color != c)
{
if (c.is_normal())
{
write_foreground_color(0);
writembs(exit_attribute_mode);
last_color2 = rgb_color_t::normal();
was_bold=0;
was_underline=0;
}
else if (! c.is_special())
{
write_foreground_color(index_for_color(c));
}
}
}
last_color = c;
last_color = c;
if( last_color2 != c2 )
{
if( c2.is_normal() )
if (last_color2 != c2)
{
if (c2.is_normal())
{
write_background_color(0);
writembs( exit_attribute_mode );
if( ! last_color.is_normal())
{
writembs(exit_attribute_mode);
if (! last_color.is_normal())
{
write_foreground_color(index_for_color(last_color));
}
}
was_bold=0;
was_underline=0;
last_color2 = c2;
}
else if ( ! c2.is_special() )
{
was_bold=0;
was_underline=0;
last_color2 = c2;
}
else if (! c2.is_special())
{
write_background_color(index_for_color(c2));
last_color2 = c2;
last_color2 = c2;
}
}
}
/*
Lastly, we set bold mode and underline mode correctly
*/
if( (enter_bold_mode != 0) && (strlen(enter_bold_mode) > 0) && !bg_set )
{
if( is_bold && !was_bold )
/*
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 )
{
writembs( tparm( enter_bold_mode ) );
}
if (is_bold && !was_bold)
{
if (enter_bold_mode)
{
writembs(tparm(enter_bold_mode));
}
}
was_bold = is_bold;
}
was_bold = is_bold;
}
if( was_underline && !is_underline )
{
writembs( exit_underline_mode );
}
if (was_underline && !is_underline)
{
writembs(exit_underline_mode);
}
if( !was_underline && is_underline )
{
writembs( enter_underline_mode );
}
was_underline = is_underline;
if (!was_underline && is_underline)
{
writembs(enter_underline_mode);
}
was_underline = is_underline;
}
/**
Default output method, simply calls write() on stdout
*/
static int writeb_internal( char c )
static int writeb_internal(char c)
{
write_loop( 1, &c, 1 );
return 0;
write_loop(1, &c, 1);
return 0;
}
int writeb( tputs_arg_t b )
int writeb(tputs_arg_t b)
{
out( b );
return 0;
out(b);
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;
size_t i;
char buff[MB_LEN_MAX+1];
size_t bytes;
mbstate_t state;
size_t i;
char buff[MB_LEN_MAX+1];
size_t bytes;
if( ( ch >= ENCODE_DIRECT_BASE) &&
( ch < ENCODE_DIRECT_BASE+256) )
{
buff[0] = ch - ENCODE_DIRECT_BASE;
bytes=1;
}
else
{
memset( &state, 0, sizeof(state) );
bytes= wcrtomb( buff, ch, &state );
switch( bytes )
if ((ch >= ENCODE_DIRECT_BASE) &&
(ch < ENCODE_DIRECT_BASE+256))
{
case (size_t)(-1):
{
return 1;
}
buff[0] = ch - ENCODE_DIRECT_BASE;
bytes=1;
}
}
else
{
memset(&state, 0, sizeof(state));
bytes= wcrtomb(buff, ch, &state);
for( i=0; i<bytes; i++ )
{
out( buff[i] );
}
return 0;
switch (bytes)
{
case (size_t)(-1):
{
return 1;
}
}
}
for (i=0; i<bytes; i++)
{
out(buff[i]);
}
return 0;
}
void writestr( const wchar_t *str )
void writestr(const wchar_t *str)
{
char *pos;
char *pos;
CHECK( str, );
CHECK(str,);
// while( *str )
// writech( *str++ );
/*
Check amount of needed space
*/
size_t len = wcstombs( 0, str, 0 );
/*
Check amount of needed space
*/
size_t len = wcstombs(0, str, 0);
if( len == (size_t)-1 )
{
debug( 1, L"Tried to print invalid wide character string" );
return;
}
if (len == (size_t)-1)
{
debug(1, L"Tried to print invalid wide character string");
return;
}
len++;
len++;
/*
Convert
*/
/*
Convert
*/
char *buffer, static_buffer[256];
if (len <= sizeof static_buffer)
buffer = static_buffer;
else
buffer = new char[len];
wcstombs( buffer,
wcstombs(buffer,
str,
len );
len);
/*
Write
*/
for( pos = buffer; *pos; pos++ )
{
out( *pos );
}
/*
Write
*/
for (pos = buffer; *pos; pos++)
{
out(*pos);
}
if (buffer != static_buffer)
delete[] buffer;
}
void writestr_ellipsis( const wchar_t *str, int max_width )
void writestr_ellipsis(const wchar_t *str, int max_width)
{
int written=0;
int tot;
int written=0;
int tot;
CHECK( str, );
CHECK(str,);
tot = my_wcswidth(str);
tot = my_wcswidth(str);
if( tot <= max_width )
{
writestr( str );
return;
}
while( *str != 0 )
{
int w = fish_wcwidth( *str );
if( written+w+fish_wcwidth( ellipsis_char )>max_width )
if (tot <= max_width)
{
break;
writestr(str);
return;
}
written+=w;
writech( *(str++) );
}
written += fish_wcwidth( ellipsis_char );
writech( ellipsis_char );
while (*str != 0)
{
int w = fish_wcwidth(*str);
if (written+w+fish_wcwidth(ellipsis_char)>max_width)
{
break;
}
written+=w;
writech(*(str++));
}
while( written < max_width )
{
written++;
writestr( L" " );
}
written += fish_wcwidth(ellipsis_char);
writech(ellipsis_char);
while (written < max_width)
{
written++;
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;
int i;
int len;
int written=0;
wchar_t *out;
int i;
int len;
int written=0;
CHECK( str, 0 );
CHECK(str, 0);
out = escape( str, 1 );
len = my_wcswidth( out );
out = escape(str, 1);
len = my_wcswidth(out);
if( max_len && (max_len < len))
{
for( i=0; (written+fish_wcwidth(out[i]))<=(max_len-1); i++ )
if (max_len && (max_len < len))
{
writech( out[i] );
written += fish_wcwidth( out[i] );
}
writech( ellipsis_char );
written += fish_wcwidth( ellipsis_char );
for (i=0; (written+fish_wcwidth(out[i]))<=(max_len-1); i++)
{
writech(out[i]);
written += fish_wcwidth(out[i]);
}
writech(ellipsis_char);
written += fish_wcwidth(ellipsis_char);
for( i=written; i<max_len; i++ )
for (i=written; i<max_len; i++)
{
writech(L' ');
written++;
}
}
else
{
writech( L' ' );
written++;
written = len;
writestr(out);
}
}
else
{
written = len;
writestr( out );
}
free( out );
return written;
free(out);
return written;
}
int output_color_code( const wcstring &val, bool is_background ) {
size_t i;
int output_color_code(const wcstring &val, bool is_background)
{
size_t i;
int color=FISH_COLOR_NORMAL;
int is_bold=0;
int is_underline=0;
int is_bold=0;
int is_underline=0;
if (val.empty())
return FISH_COLOR_NORMAL;
if (val.empty())
return FISH_COLOR_NORMAL;
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);
wcstring color_name;
if (is_background) {
if (is_background)
{
// look for something like "--background=red"
const wcstring prefix = L"--background=";
if (string_prefixes_string(prefix, next)) {
if (string_prefixes_string(prefix, next))
{
color_name = wcstring(next, prefix.size());
}
} else {
}
else
{
if (next == L"--bold" || next == L"-o")
is_bold = true;
else if (next == L"--underline" || next == L"-u")
@ -597,10 +628,11 @@ int output_color_code( const wcstring &val, bool is_background ) {
color_name = next;
}
if (! color_name.empty()) {
for( i=0; i<COLORS; i++ )
if (! color_name.empty())
{
for (i=0; i<COLORS; i++)
{
if( wcscasecmp( col[i], color_name.c_str() ) == 0 )
if (wcscasecmp(col[i], color_name.c_str()) == 0)
{
color = col_idx[i];
break;
@ -608,30 +640,36 @@ 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_underline=0;
int is_underline=0;
std::vector<rgb_color_t> candidates;
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);
wcstring color_name;
if (is_background) {
if (is_background)
{
// look for something like "--background=red"
const wcstring prefix = L"--background=";
if (string_prefixes_string(prefix, next)) {
if (string_prefixes_string(prefix, next))
{
color_name = wcstring(next, prefix.size());
}
} else {
}
else
{
if (next == L"--bold" || next == L"-o")
is_bold = true;
else if (next == L"--underline" || next == L"-u")
@ -640,9 +678,11 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) {
color_name = next;
}
if (! color_name.empty()) {
if (! color_name.empty())
{
rgb_color_t color = rgb_color_t(color_name);
if (! color.is_none()) {
if (! color.is_none())
{
candidates.push_back(color);
}
}
@ -650,7 +690,8 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) {
// Pick the best candidate
rgb_color_t first_rgb = rgb_color_t::none(), first_named = rgb_color_t::none();
for (size_t i=0; i < candidates.size(); i++) {
for (size_t i=0; i < candidates.size(); i++)
{
const rgb_color_t &color = candidates.at(i);
if (color.is_rgb() && first_rgb.is_none())
first_rgb = color;
@ -660,9 +701,12 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) {
// If we have both RGB and named colors, then prefer rgb if term256 is supported
rgb_color_t result;
if ((!first_rgb.is_none() && output_get_supports_term256()) || first_named.is_none()) {
if ((!first_rgb.is_none() && output_get_supports_term256()) || first_named.is_none())
{
result = first_rgb;
} else {
}
else
{
result = first_named;
}
@ -680,9 +724,9 @@ rgb_color_t parse_color( const wcstring &val, bool is_background ) {
return result;
}
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()

View file

@ -17,18 +17,18 @@
*/
enum
{
FISH_COLOR_BLACK,
FISH_COLOR_RED,
FISH_COLOR_GREEN,
FISH_COLOR_YELLOW,
FISH_COLOR_BLUE,
FISH_COLOR_MAGENTA,
FISH_COLOR_CYAN,
FISH_COLOR_WHITE,
/** The default fg color of the terminal */
FISH_COLOR_NORMAL,
FISH_COLOR_IGNORE,
FISH_COLOR_RESET
FISH_COLOR_BLACK,
FISH_COLOR_RED,
FISH_COLOR_GREEN,
FISH_COLOR_YELLOW,
FISH_COLOR_BLUE,
FISH_COLOR_MAGENTA,
FISH_COLOR_CYAN,
FISH_COLOR_WHITE,
/** The default fg color of the terminal */
FISH_COLOR_NORMAL,
FISH_COLOR_IGNORE,
FISH_COLOR_RESET
}
;
@ -104,41 +104,41 @@ void set_color(rgb_color_t c, rgb_color_t c2);
as the sending function. But a weird bug on PPC Linux means that on
this platform, write is instead used directly.
*/
int writembs_internal( char *str );
int writembs_internal(char *str);
/**
Write a wide character using the output method specified using output_set_writer().
*/
int writech( wint_t ch );
int writech(wint_t ch);
/**
Write a wide character string to FD 1.
*/
void writestr( const wchar_t *str );
void writestr(const wchar_t *str);
/**
Write a wide character string to FD 1. If the string is wider than
the specified maximum, truncate and ellipsize it.
*/
void writestr_ellipsis( const wchar_t *str, int max_width );
void writestr_ellipsis(const wchar_t *str, int max_width);
/**
Escape and write a string to fd 1
*/
int write_escaped_str( const wchar_t *str, int max_len );
int write_escaped_str(const wchar_t *str, int max_len);
/**
Return the internal color code representing the specified color
*/
int output_color_code( const wcstring &val, bool is_background );
rgb_color_t parse_color( const wcstring &val, bool is_background );
int output_color_code(const wcstring &val, bool is_background);
rgb_color_t parse_color(const wcstring &val, bool is_background);
/**
This is for writing process notification messages. Has to write to
stdout, so clr_eol and such functions will work correctly. Not an
issue since this function is only used in interactive mode anyway.
*/
int writeb( tputs_arg_t b );
int writeb(tputs_arg_t b);
/**
Set the function used for writing in move_cursor, writespace and
@ -146,7 +146,7 @@ int writeb( tputs_arg_t b );
default, the write call is used to give completely unbuffered
output to stdout.
*/
void output_set_writer( int (*writer)(char) );
void output_set_writer(int (*writer)(char));
/**
Return the current output writer
@ -154,7 +154,7 @@ void output_set_writer( int (*writer)(char) );
int (*output_get_writer())(char) ;
/** Set the terminal name */
void output_set_term( const wchar_t *term );
void output_set_term(const wchar_t *term);
/** Return the terminal name */
const wchar_t *output_get_term();

File diff suppressed because it is too large Load diff

View file

@ -22,10 +22,10 @@
\return -1 on syntax error, 0 if no subshells exist and 1 on sucess
*/
int parse_util_locate_cmdsubst( const wchar_t *in,
wchar_t **begin,
wchar_t **end,
int flags );
int parse_util_locate_cmdsubst(const wchar_t *in,
wchar_t **begin,
wchar_t **end,
int flags);
/**
Find the beginning and end of the command substitution under the
@ -39,10 +39,10 @@ int parse_util_locate_cmdsubst( const wchar_t *in,
\param a the start of the searched string
\param b the end of the searched string
*/
void parse_util_cmdsubst_extent( const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b );
void parse_util_cmdsubst_extent(const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b);
/**
Find the beginning and end of the process definition under the cursor
@ -52,10 +52,10 @@ void parse_util_cmdsubst_extent( const wchar_t *buff,
\param a the start of the searched string
\param b the end of the searched string
*/
void parse_util_process_extent( const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b );
void parse_util_process_extent(const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b);
/**
@ -66,10 +66,10 @@ void parse_util_process_extent( const wchar_t *buff,
\param a the start of the searched string
\param b the end of the searched string
*/
void parse_util_job_extent( const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b );
void parse_util_job_extent(const wchar_t *buff,
size_t cursor_pos,
const wchar_t **a,
const wchar_t **b);
/**
Find the beginning and end of the token under the cursor and the
@ -83,46 +83,46 @@ void parse_util_job_extent( const wchar_t *buff,
\param prev_begin the start o 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,
size_t cursor_pos,
const wchar_t **tok_begin,
const wchar_t **tok_end,
const wchar_t **prev_begin,
const wchar_t **prev_end );
void parse_util_token_extent(const wchar_t *buff,
size_t cursor_pos,
const wchar_t **tok_begin,
const wchar_t **tok_end,
const wchar_t **prev_begin,
const wchar_t **prev_end);
/**
Get the linenumber at the specified character offset
*/
int parse_util_lineno( const wchar_t *str, size_t len );
int parse_util_lineno(const wchar_t *str, size_t len);
/**
Calculate the line number of the specified cursor position
*/
int parse_util_get_line_from_offset( const wcstring &str, size_t pos );
int parse_util_get_line_from_offset(const wcstring &str, size_t pos);
/**
Get the offset of the first character on the specified line
*/
size_t parse_util_get_offset_from_line( const wcstring &str, int line );
size_t parse_util_get_offset_from_line(const wcstring &str, int line);
/**
Return the total offset of the buffer for the cursor position nearest to the specified poition
*/
size_t parse_util_get_offset( const wcstring &str, int line, long line_offset );
size_t parse_util_get_offset(const wcstring &str, int line, long line_offset);
/**
Set the argv environment variable to the specified null-terminated
array of strings.
*/
void parse_util_set_argv( const wchar_t * const *argv, const wcstring_list_t &named_arguments );
void parse_util_set_argv(const wchar_t * const *argv, const wcstring_list_t &named_arguments);
/**
Make a duplicate of the specified string, unescape wildcard
characters but not performing any other character transformation.
*/
wchar_t *parse_util_unescape_wildcards( const wchar_t *in );
wchar_t *parse_util_unescape_wildcards(const wchar_t *in);
/**
Calculates information on the parameter at the specified index.
@ -133,12 +133,12 @@ wchar_t *parse_util_unescape_wildcards( const wchar_t *in );
\param offset If not NULL, get_param will store the offset to the beginning of the parameter.
\param type If not NULL, get_param will store the token type as returned by tok_last.
*/
void parse_util_get_parameter_info( const wcstring &cmd, const size_t pos, wchar_t *quote, size_t *offset, int *type );
void parse_util_get_parameter_info(const wcstring &cmd, const size_t pos, wchar_t *quote, size_t *offset, int *type);
/**
Attempts to escape the string 'cmd' using the given quote type, as determined by the quote character. The quote can be a single quote or double quote, or L'\0' to indicate no quoting (and thus escaping should be with backslashes).
*/
wcstring parse_util_escape_string_with_quote( const wcstring &cmd, wchar_t quote);
wcstring parse_util_escape_string_with_quote(const wcstring &cmd, wchar_t quote);
#endif

5051
parser.cpp

File diff suppressed because it is too large Load diff

290
parser.h
View file

@ -21,24 +21,26 @@
*/
struct event_blockage_t
{
/**
The types of events to block. This is interpreted as a bitset
whete the value is 1 for every bit corresponding to a blocked
event type. For example, if EVENT_VARIABLE type events should
be blocked, (type & 1<<EVENT_BLOCKED) should be set.
/**
The types of events to block. This is interpreted as a bitset
whete the value is 1 for every bit corresponding to a blocked
event type. For example, if EVENT_VARIABLE type events should
be blocked, (type & 1<<EVENT_BLOCKED) should be set.
Note that EVENT_ANY can be used to specify any event.
*/
unsigned int typemask;
Note that EVENT_ANY can be used to specify any event.
*/
unsigned int typemask;
};
typedef std::list<event_blockage_t> event_blockage_list_t;
inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls, int type) {
for (event_blockage_list_t::const_iterator iter = ebls.begin(); iter != ebls.end(); ++iter) {
if( iter->typemask & (1<<EVENT_ANY ) )
inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls, int type)
{
for (event_blockage_list_t::const_iterator iter = ebls.begin(); iter != ebls.end(); ++iter)
{
if (iter->typemask & (1<<EVENT_ANY))
return true;
if( iter->typemask & (1<<type) )
if (iter->typemask & (1<<type))
return true;
}
return false;
@ -50,20 +52,20 @@ inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls, int
*/
enum block_type_t
{
WHILE, /**< While loop block */
FOR, /**< For loop block */
IF, /**< If block */
FUNCTION_DEF, /**< Function definition block */
FUNCTION_CALL, /**< Function invocation block */
FUNCTION_CALL_NO_SHADOW, /**< Function invocation block with no variable shadowing */
SWITCH, /**< Switch block */
FAKE, /**< Fake block */
SUBST, /**< Command substitution scope */
TOP, /**< Outermost block */
BEGIN, /**< Unconditional block */
SOURCE, /**< Block created by the . (source) builtin */
EVENT, /**< Block created on event notifier invocation */
BREAKPOINT, /**< Breakpoint block */
WHILE, /**< While loop block */
FOR, /**< For loop block */
IF, /**< If block */
FUNCTION_DEF, /**< Function definition block */
FUNCTION_CALL, /**< Function invocation block */
FUNCTION_CALL_NO_SHADOW, /**< Function invocation block with no variable shadowing */
SWITCH, /**< Switch block */
FAKE, /**< Fake block */
SUBST, /**< Command substitution scope */
TOP, /**< Outermost block */
BEGIN, /**< Unconditional block */
SOURCE, /**< Block created by the . (source) builtin */
EVENT, /**< Block created on event notifier invocation */
BREAKPOINT, /**< Breakpoint block */
}
;
@ -72,67 +74,73 @@ enum block_type_t
*/
struct block_t
{
protected:
protected:
/** Protected constructor. Use one of the subclasses below. */
block_t(block_type_t t);
private:
const block_type_t block_type; /**< Type of block. */
private:
const block_type_t block_type; /**< Type of block. */
bool made_fake;
public:
block_type_t type() const { return this->made_fake ? FAKE : this->block_type; }
public:
block_type_t type() const
{
return this->made_fake ? FAKE : this->block_type;
}
/** 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 had_command; /**< Set to non-zero once a command has been executed in this block */
int tok_pos; /**< The start index of the block */
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 */
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.
*/
int loop_status;
/**
Status for the current loop block. Can be any of the values from the loop_status enum.
*/
int loop_status;
/**
The job that is currently evaluated in the specified block.
*/
job_t *job;
/**
The job that is currently evaluated in the specified block.
*/
job_t *job;
#if 0
union
{
int while_state; /**< True if the loop condition has not yet been evaluated*/
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 */
wchar_t *switch_value; /**< The value to test in a switch block */
const wchar_t *source_dest; /**< The name of the file to source*/
event_t *event; /**<The event that triggered this block */
wchar_t *function_call_name;
} param1;
union
{
int while_state; /**< True if the loop condition has not yet been evaluated*/
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 */
wchar_t *switch_value; /**< The value to test in a switch block */
const wchar_t *source_dest; /**< The name of the file to source*/
event_t *event; /**<The event that triggered this block */
wchar_t *function_call_name;
} param1;
#endif
/**
Name of file that created this block
*/
const wchar_t *src_filename;
/**
Name of file that created this block
*/
const wchar_t *src_filename;
/**
Line number where this block was created
*/
int src_lineno;
/**
Line number where this block was created
*/
int src_lineno;
/** Whether we should pop the environment variable stack when we're popped off of the block stack */
bool wants_pop_env;
/** List of event blocks. */
event_blockage_list_t event_blocks;
/** List of event blocks. */
event_blockage_list_t event_blocks;
/**
Next outer block
*/
block_t *outer;
*/
block_t *outer;
/** Destructor */
virtual ~block_t();
@ -213,9 +221,9 @@ struct breakpoint_block_t : public block_t
*/
enum loop_status
{
LOOP_NORMAL, /**< Current loop block executed as normal */
LOOP_BREAK, /**< Current loop block should be removed */
LOOP_CONTINUE, /**< Current loop block should be skipped */
LOOP_NORMAL, /**< Current loop block executed as normal */
LOOP_BREAK, /**< Current loop block should be removed */
LOOP_CONTINUE, /**< Current loop block should be skipped */
};
@ -224,9 +232,9 @@ enum loop_status
*/
enum while_status
{
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_TESTED, /**< This is not the first command in the 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_TESTED, /**< This is not the first command in the loop */
}
;
@ -236,59 +244,62 @@ enum while_status
*/
enum parser_error
{
/**
No error
*/
NO_ERR=0,
/**
An error in the syntax
*/
SYNTAX_ERROR,
/**
Error occured while evaluating commands
*/
EVAL_ERROR,
/**
Error while evaluating cmdsubst
*/
CMDSUBST_ERROR,
/**
No error
*/
NO_ERR=0,
/**
An error in the syntax
*/
SYNTAX_ERROR,
/**
Error occured while evaluating commands
*/
EVAL_ERROR,
/**
Error while evaluating cmdsubst
*/
CMDSUBST_ERROR,
};
enum parser_type_t {
enum parser_type_t
{
PARSER_TYPE_NONE,
PARSER_TYPE_GENERAL,
PARSER_TYPE_FUNCTIONS_ONLY,
PARSER_TYPE_COMPLETIONS_ONLY,
PARSER_TYPE_ERRORS_ONLY
PARSER_TYPE_ERRORS_ONLY
};
struct profile_item_t {
/**
Time spent executing the specified command, including parse time for nested blocks.
*/
int exec;
/**
Time spent parsing the specified command, including execution time for command substitutions.
*/
int parse;
/**
The block level of the specified command. nested blocks and command substitutions both increase the block level.
*/
size_t level;
/**
If the execution of this command was skipped.
*/
int skipped;
/**
The command string.
*/
wcstring cmd;
struct profile_item_t
{
/**
Time spent executing the specified command, including parse time for nested blocks.
*/
int exec;
/**
Time spent parsing the specified command, including execution time for command substitutions.
*/
int parse;
/**
The block level of the specified command. nested blocks and command substitutions both increase the block level.
*/
size_t level;
/**
If the execution of this command was skipped.
*/
int skipped;
/**
The command string.
*/
wcstring cmd;
};
struct tokenizer;
class parser_t {
private:
class parser_t
{
private:
enum parser_type_t parser_type;
std::vector<block_t> blocks;
@ -333,15 +344,15 @@ class parser_t {
parser_t(const parser_t&);
parser_t& operator=(const parser_t&);
void parse_job_argument_list( process_t *p, job_t *j, tokenizer *tok, std::vector<completion_t>&, bool );
int parse_job( process_t *p, job_t *j, tokenizer *tok );
void skipped_exec( job_t * j );
void eval_job( tokenizer *tok );
int parser_test_argument( const wchar_t *arg, wcstring *out, const wchar_t *prefix, int offset );
void print_errors( wcstring &target, const wchar_t *prefix );
void parse_job_argument_list(process_t *p, job_t *j, tokenizer *tok, std::vector<completion_t>&, bool);
int parse_job(process_t *p, job_t *j, tokenizer *tok);
void skipped_exec(job_t * j);
void eval_job(tokenizer *tok);
int parser_test_argument(const wchar_t *arg, wcstring *out, const wchar_t *prefix, int offset);
void print_errors(wcstring &target, const wchar_t *prefix);
void print_errors_stderr();
public:
public:
std::vector<profile_item_t> profile_items;
/**
@ -381,7 +392,7 @@ class parser_t {
\return 0 on success, 1 otherwise
*/
int eval( const wcstring &cmdStr, const io_chain_t &io, enum block_type_t block_type );
int eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type_t block_type);
/**
Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens.
@ -390,11 +401,11 @@ class parser_t {
\param line Line to evaluate
\param output List to insert output to
*/
/**
\param line Line to evaluate
\param output List to insert output to
*/
int eval_args( const wchar_t *line, std::vector<completion_t> &output );
/**
\param line Line to evaluate
\param output List to insert output to
*/
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
@ -403,7 +414,7 @@ class parser_t {
\param p The character offset at which the error occured
\param str The printf-style error message filter
*/
void error( int ec, int p, const wchar_t *str, ... );
void error(int ec, int p, const wchar_t *str, ...);
/**
Returns a string describing the current parser pisition in the format 'FILENAME (line LINE_NUMBER): LINE'.
@ -426,22 +437,25 @@ class parser_t {
int get_job_pos() const;
/** Set the current position in the latest string of the tokenizer. */
void set_pos( int p);
void set_pos(int p);
/** Get the string currently parsed */
const wchar_t *get_buffer() const;
/** Get the list of jobs */
job_list_t &job_list() { return my_job_list; }
job_list_t &job_list()
{
return my_job_list;
}
/** Pushes the block. pop_block will call delete on it. */
void push_block( block_t *newv );
void push_block(block_t *newv);
/** Remove the outermost block namespace */
void pop_block();
/** Return a description of the given blocktype */
const wchar_t *get_block_desc( int block ) const;
const wchar_t *get_block_desc(int block) const;
/** Create a job */
job_t *job_create();
@ -456,7 +470,7 @@ class parser_t {
job_t *job_get(int job_id);
/** Returns the job with the given pid */
job_t *job_get_from_pid( int pid );
job_t *job_get_from_pid(int pid);
/**
Test if the specified string can be parsed, or if more bytes need
@ -470,7 +484,7 @@ class parser_t {
\param out if non-null, any errors in the command will be filled out into this buffer
\param prefix the prefix string to prepend to each error message written to the \c out buffer
*/
int test( const wchar_t * buff, int *block_level, wcstring *out, const wchar_t *prefix );
int test(const wchar_t * buff, int *block_level, wcstring *out, const wchar_t *prefix);
/**
Test if the specified string can be parsed as an argument list,
@ -478,14 +492,14 @@ class parser_t {
string contains errors, and the second bit is set if the string
contains an unclosed block.
*/
int test_args( const wchar_t * buff, wcstring *out, const wchar_t *prefix );
int test_args(const wchar_t * buff, wcstring *out, const wchar_t *prefix);
/**
Tell the parser that the specified function may not be run if not
inside of a conditional block. This is to remove some possibilities
of infinite recursion.
*/
void forbid_function( const wcstring &function );
void forbid_function(const wcstring &function);
/**
Undo last call to parser_forbid_function().
*/
@ -507,7 +521,7 @@ class parser_t {
\param s the string to test
\param min_match is the minimum number of characters that must match in a long style option, i.e. the longest common prefix between --help and any other option. If less than 3, 3 will be assumed.
*/
int is_help( const wchar_t *s, int min_match ) const;
int is_help(const wchar_t *s, int min_match) const;
/**
Returns the file currently evaluated by the parser. This can be
@ -519,10 +533,10 @@ class parser_t {
/**
Write a stack trace starting at the specified block to the specified wcstring
*/
void stack_trace( block_t *b, wcstring &buff);
void stack_trace(block_t *b, wcstring &buff);
int get_block_type( const wchar_t *cmd ) const;
const wchar_t *get_block_command( int type ) const;
int get_block_type(const wchar_t *cmd) const;
const wchar_t *get_block_command(int type) const;
};

View file

@ -14,62 +14,67 @@ Functions having to do with parser keywords, like testing if a function is a blo
#include "parser_keywords.h"
bool parser_keywords_is_switch( const wcstring &cmd )
bool parser_keywords_is_switch(const wcstring &cmd)
{
if (cmd == L"--") {
return ARG_SKIP;
} else if (! cmd.empty() && cmd.at(0) == L'-') {
if (cmd == L"--")
{
return ARG_SKIP;
}
else if (! cmd.empty() && cmd.at(0) == L'-')
{
return ARG_SWITCH;
} else {
}
else
{
return ARG_NON_SWITCH;
}
}
bool parser_keywords_skip_arguments( const wcstring &cmd )
bool parser_keywords_skip_arguments(const wcstring &cmd)
{
return contains( cmd,
L"else",
L"begin" );
return contains(cmd,
L"else",
L"begin");
}
bool parser_keywords_is_subcommand( const wcstring &cmd )
bool parser_keywords_is_subcommand(const wcstring &cmd)
{
return parser_keywords_skip_arguments( cmd ) ||
contains( cmd,
L"command",
L"builtin",
L"while",
L"exec",
L"if",
L"and",
L"or",
L"not" );
return parser_keywords_skip_arguments(cmd) ||
contains(cmd,
L"command",
L"builtin",
L"while",
L"exec",
L"if",
L"and",
L"or",
L"not");
}
bool parser_keywords_is_block( const wcstring &word)
bool parser_keywords_is_block(const wcstring &word)
{
return contains( word,
L"for",
L"while",
L"if",
L"function",
L"switch",
L"begin" );
return contains(word,
L"for",
L"while",
L"if",
L"function",
L"switch",
L"begin");
}
bool parser_keywords_is_reserved( const wcstring &word)
bool parser_keywords_is_reserved(const wcstring &word)
{
return parser_keywords_is_block(word) ||
parser_keywords_is_subcommand( word ) ||
contains( word,
L"end",
L"case",
L"else",
L"return",
L"continue",
L"break" );
return parser_keywords_is_block(word) ||
parser_keywords_is_subcommand(word) ||
contains(word,
L"end",
L"case",
L"else",
L"return",
L"continue",
L"break");
}

View file

@ -11,9 +11,9 @@ Functions having to do with parser keywords, like testing if a function is a blo
*/
enum
{
ARG_NON_SWITCH,
ARG_SWITCH,
ARG_SKIP
ARG_NON_SWITCH,
ARG_SWITCH,
ARG_SKIP
};
@ -22,7 +22,7 @@ enum
Check if the specified argument is a switch. Return ARG_SWITCH if yes,
ARG_NON_SWITCH if no and ARG_SKIP if the argument is '--'
*/
bool parser_keywords_is_switch( const wcstring &cmd );
bool parser_keywords_is_switch(const wcstring &cmd);
/**
@ -32,7 +32,7 @@ bool parser_keywords_is_switch( const wcstring &cmd );
\return 1 of the command parameter is a command, 0 otherwise
*/
bool parser_keywords_is_subcommand( const wcstring &cmd );
bool parser_keywords_is_subcommand(const wcstring &cmd);
/**
Tests if the specified command is a reserved word, i.e. if it is
@ -43,20 +43,20 @@ bool parser_keywords_is_subcommand( const wcstring &cmd );
\param word The command name to test
\return 1 of the command parameter is a command, 0 otherwise
*/
bool parser_keywords_is_reserved( const wcstring &word );
bool parser_keywords_is_reserved(const wcstring &word);
/**
Test if the specified string is command that opens a new block
*/
bool parser_keywords_is_block( const wcstring &word);
bool parser_keywords_is_block(const wcstring &word);
/**
Check if the specified command is one of the builtins that cannot
have arguments, any followin argument is interpreted as a new
command
*/
bool parser_keywords_skip_arguments( const wcstring &cmd );
bool parser_keywords_skip_arguments(const wcstring &cmd);
#endif

398
path.cpp
View file

@ -25,110 +25,110 @@
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 (cmd.find(L'/') != wcstring::npos)
{
if( waccess( cmd, X_OK )==0 )
if (cmd.find(L'/') != wcstring::npos)
{
struct stat buff;
if(wstat( cmd, &buff ))
{
return false;
}
if( S_ISREG(buff.st_mode) )
if (waccess(cmd, X_OK)==0)
{
struct stat buff;
if (wstat(cmd, &buff))
{
if (out_path)
return false;
}
if (S_ISREG(buff.st_mode))
{
if (out_path)
out_path->assign(cmd);
return true;
}
else
{
errno = EACCES;
return false;
}
else
{
errno = EACCES;
return false;
}
}
else
{
struct stat buff;
wstat(cmd, &buff);
return false;
}
}
else
{
struct stat buff;
wstat( cmd, &buff );
return false;
}
}
else
{
wcstring bin_path;
if (! bin_path_var.missing())
if (! bin_path_var.missing())
{
bin_path = bin_path_var;
}
else
{
if (contains( PREFIX L"/bin", L"/bin", L"/usr/bin" ))
{
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
}
else
{
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
}
}
{
if (contains(PREFIX L"/bin", L"/bin", L"/usr/bin"))
{
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
}
else
{
bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
}
}
wcstring nxt_path;
wcstokenizer tokenizer(bin_path, ARRAY_SEP_STR);
while (tokenizer.next(nxt_path))
{
while (tokenizer.next(nxt_path))
{
if (nxt_path.empty())
continue;
append_path_component(nxt_path, cmd);
if( waccess( nxt_path, X_OK )==0 )
{
struct stat buff;
if( wstat( nxt_path, &buff )==-1 )
{
if( errno != EACCES )
{
wperror( L"stat" );
}
continue;
}
if( S_ISREG(buff.st_mode) )
{
if (waccess(nxt_path, X_OK)==0)
{
struct stat buff;
if (wstat(nxt_path, &buff)==-1)
{
if (errno != EACCES)
{
wperror(L"stat");
}
continue;
}
if (S_ISREG(buff.st_mode))
{
if (out_path)
out_path->swap(nxt_path);
return true;
}
err = EACCES;
return true;
}
err = EACCES;
}
else
{
switch( errno )
{
case ENOENT:
case ENAMETOOLONG:
case EACCES:
case ENOTDIR:
break;
default:
{
debug( 1,
MISSING_COMMAND_ERR_MSG,
nxt_path.c_str() );
wperror( L"access" );
}
}
else
{
switch (errno)
{
case ENOENT:
case ENAMETOOLONG:
case EACCES:
case ENOTDIR:
break;
default:
{
debug(1,
MISSING_COMMAND_ERR_MSG,
nxt_path.c_str());
wperror(L"access");
}
}
}
}
}
}
}
errno = err;
return false;
errno = err;
return false;
}
bool path_get_path(const wcstring &cmd, wcstring *out_path, const env_vars_snapshot_t &vars)
@ -143,36 +143,37 @@ 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)
{
wchar_t *res = 0;
int err = ENOENT;
wchar_t *res = 0;
int err = ENOENT;
bool success = false;
const wchar_t *const dir = dir_str.c_str();
if( dir[0] == L'/'|| (wcsncmp( dir, L"./", 2 )==0) )
{
struct stat buf;
if( wstat( dir, &buf ) == 0 )
if (dir[0] == L'/'|| (wcsncmp(dir, L"./", 2)==0))
{
if( S_ISDIR(buf.st_mode) )
{
result = dir_str;
struct stat buf;
if (wstat(dir, &buf) == 0)
{
if (S_ISDIR(buf.st_mode))
{
result = dir_str;
success = true;
}
else
{
err = ENOTDIR;
}
}
else
{
err = ENOTDIR;
}
}
}
}
else
{
else
{
wcstring path = L".";
// Respect CDPATH
env_var_t cdpath = env_get_string(L"CDPATH");
if (! cdpath.missing_or_empty()) {
if (! cdpath.missing_or_empty())
{
path = cdpath.c_str();
}
@ -186,44 +187,44 @@ bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env
wcstring whole_path = next_path;
append_path_component(whole_path, dir);
struct stat buf;
if( wstat( whole_path, &buf ) == 0 )
{
if( S_ISDIR(buf.st_mode) )
{
struct stat buf;
if (wstat(whole_path, &buf) == 0)
{
if (S_ISDIR(buf.st_mode))
{
result = whole_path;
success = true;
break;
}
else
{
err = ENOTDIR;
}
}
else
{
if( lwstat( whole_path, &buf ) == 0 )
{
err = EROTTEN;
}
}
break;
}
else
{
err = ENOTDIR;
}
}
else
{
if (lwstat(whole_path, &buf) == 0)
{
err = EROTTEN;
}
}
}
}
if( !success )
{
errno = err;
}
if (!success)
{
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)
{
int err = ENOENT;
if (dir.empty())
return false;
int err = ENOENT;
if (dir.empty())
return false;
if (wd)
{
@ -232,19 +233,24 @@ bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, cons
}
wcstring_list_t paths;
if (dir.at(0) == L'/') {
if (dir.at(0) == L'/')
{
/* Absolute path */
paths.push_back(dir);
} else if (string_prefixes_string(L"./", dir) ||
string_prefixes_string(L"../", dir) ||
dir == L"." || dir == L"..") {
}
else if (string_prefixes_string(L"./", dir) ||
string_prefixes_string(L"../", dir) ||
dir == L"." || dir == L"..")
{
/* Path is relative to the working directory */
wcstring path;
if (wd)
path.append(wd);
path.append(dir);
paths.push_back(path);
} else {
}
else
{
// Respect CDPATH
env_var_t path = env_vars.get(L"CDPATH");
if (path.missing_or_empty())
@ -255,7 +261,8 @@ bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, cons
while (tokenizer.next(nxt_path))
{
if (nxt_path == L"." && wd != NULL) {
if (nxt_path == L"." && wd != NULL)
{
// nxt_path is just '.', and we have a working directory, so use the wd instead
// TODO: if nxt_path starts with ./ we need to replace the . with the wd
nxt_path = wd;
@ -274,27 +281,28 @@ bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, cons
}
bool success = false;
for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter) {
struct stat buf;
const wcstring &dir = *iter;
if( wstat( dir, &buf ) == 0 )
for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter)
{
if( S_ISDIR(buf.st_mode) )
{
struct stat buf;
const wcstring &dir = *iter;
if (wstat(dir, &buf) == 0)
{
if (S_ISDIR(buf.st_mode))
{
success = true;
if (out)
out->assign(dir);
break;
}
else
{
err = ENOTDIR;
}
}
}
else
{
err = ENOTDIR;
}
}
}
if (! success)
errno = err;
errno = err;
return success;
}
@ -305,9 +313,9 @@ bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path, const wch
bool result = false;
if (string_prefixes_string(L"/", exp_path) ||
string_prefixes_string(L"./", exp_path) ||
string_prefixes_string(L"../", exp_path) ||
exp_path == L"..")
string_prefixes_string(L"./", exp_path) ||
string_prefixes_string(L"../", exp_path) ||
exp_path == L"..")
{
/* These paths can be implicit cd, so see if you cd to the path. Note that a single period cannot (that's used for sourcing files anyways) */
result = path_get_cdpath(exp_path, out_path, wd, vars);
@ -317,41 +325,41 @@ bool path_can_be_implicit_cd(const wcstring &path, wcstring *out_path, const wch
bool path_get_config(wcstring &path)
{
int done = 0;
wcstring res;
int done = 0;
wcstring res;
const env_var_t xdg_dir = env_get_string( L"XDG_CONFIG_HOME" );
if( ! xdg_dir.missing() )
{
res = xdg_dir + L"/fish";
if( !create_directory( res ) )
const env_var_t xdg_dir = env_get_string(L"XDG_CONFIG_HOME");
if (! xdg_dir.missing())
{
done = 1;
res = xdg_dir + L"/fish";
if (!create_directory(res))
{
done = 1;
}
}
}
else
{
const env_var_t home = env_get_string( L"HOME" );
if( ! home.missing() )
else
{
res = home + L"/.config/fish";
if( !create_directory( res ) )
{
done = 1;
}
const env_var_t home = env_get_string(L"HOME");
if (! home.missing())
{
res = home + L"/.config/fish";
if (!create_directory(res))
{
done = 1;
}
}
}
}
if( done )
{
if (done)
{
path = res;
return true;
}
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." ));
return false;
}
}
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."));
return false;
}
}
@ -359,25 +367,28 @@ static void replace_all(wcstring &str, const wchar_t *needle, const wchar_t *rep
{
size_t needle_len = wcslen(needle);
size_t offset = 0;
while((offset = str.find(needle, offset)) != wcstring::npos)
while ((offset = str.find(needle, offset)) != wcstring::npos)
{
str.replace(offset, needle_len, replacement);
offset += needle_len;
}
}
void path_make_canonical( wcstring &path )
void path_make_canonical(wcstring &path)
{
/* Remove double slashes */
size_t size;
do {
do
{
size = path.size();
replace_all(path, L"//", L"/");
} while (path.size() != size);
}
while (path.size() != size);
/* Remove trailing slashes, except don't remove the first one */
while (size-- > 1) {
while (size-- > 1)
{
if (path.at(size) != L'/')
break;
}
@ -389,41 +400,56 @@ bool path_is_valid(const wcstring &path, const wcstring &working_directory)
{
bool path_is_valid;
/* Some special paths are always valid */
if (path.empty()) {
if (path.empty())
{
path_is_valid = false;
} else if (path == L"." || path == L"./") {
}
else if (path == L"." || path == L"./")
{
path_is_valid = true;
} else if (path == L".." || path == L"../") {
}
else if (path == L".." || path == L"../")
{
path_is_valid = (! working_directory.empty() && working_directory != L"/");
} else if (path.at(0) != '/') {
}
else if (path.at(0) != '/')
{
/* Prepend the working directory. Note that we know path is not empty here. */
wcstring tmp = working_directory;
tmp.append(path);
path_is_valid = (0 == waccess(tmp, F_OK));
} else {
}
else
{
/* Simple check */
path_is_valid = (0 == waccess(path, F_OK));
}
return path_is_valid;
}
bool paths_are_same_file(const wcstring &path1, const wcstring &path2) {
bool paths_are_same_file(const wcstring &path1, const wcstring &path2)
{
if (path1 == path2)
return true;
struct stat s1, s2;
if (wstat(path1, &s1) == 0 && wstat(path2, &s2) == 0) {
if (wstat(path1, &s1) == 0 && wstat(path2, &s2) == 0)
{
return s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
} else {
}
else
{
return false;
}
}
wcstring get_working_directory(void) {
wcstring get_working_directory(void)
{
wcstring wd = L"./";
wchar_t dir_path[4096];
const wchar_t *cwd = wgetcwd( dir_path, 4096 );
if (cwd) {
const wchar_t *cwd = wgetcwd(dir_path, 4096);
if (cwd)
{
wd = cwd;
/* Make sure the working directory ends with a slash */
if (! wd.empty() && wd.at(wd.size() - 1) != L'/')

2
path.h
View file

@ -71,7 +71,7 @@ bool path_can_be_implicit_cd(const wcstring &path,
Remove double slashes and trailing slashes from a path,
e.g. transform foo//bar/ into foo/bar. The string is modified in-place.
*/
void path_make_canonical( wcstring &path );
void path_make_canonical(wcstring &path);
bool path_is_valid(const wcstring &path, const wcstring &working_directory);

View file

@ -42,21 +42,21 @@ 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.
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 (!j->pgid)
if (job_get_flag(j, JOB_CONTROL))
{
j->pgid = p->pid;
}
if (!j->pgid)
{
j->pgid = p->pid;
}
if( setpgid (p->pid, j->pgid) )
{
if( getpgid( p->pid) != j->pgid && print_errors )
{
if (setpgid(p->pid, j->pgid))
{
if (getpgid(p->pid) != j->pgid && print_errors)
{
char pid_buff[128];
char job_id_buff[128];
char getpgid_buff[128];
@ -64,41 +64,41 @@ int set_child_group( job_t *j, process_t *p, int print_errors )
format_long_safe(pid_buff, p->pid);
format_long_safe(job_id_buff, j->job_id);
format_long_safe(getpgid_buff, getpgid( p->pid));
format_long_safe(getpgid_buff, getpgid(p->pid));
format_long_safe(job_pgid_buff, j->pgid);
debug_safe( 1,
"Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
pid_buff,
p->argv0_cstr(),
job_id_buff,
j->command_cstr(),
getpgid_buff,
job_pgid_buff );
debug_safe(1,
"Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
pid_buff,
p->argv0_cstr(),
job_id_buff,
j->command_cstr(),
getpgid_buff,
job_pgid_buff);
wperror( L"setpgid" );
res = -1;
}
wperror(L"setpgid");
res = -1;
}
}
}
}
else
{
j->pgid = getpid();
}
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
{
if( tcsetpgrp (0, j->pgid) && print_errors )
else
{
j->pgid = getpid();
}
if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND))
{
if (tcsetpgrp(0, j->pgid) && print_errors)
{
char job_id_buff[128];
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() );
wperror( L"tcsetpgrp" );
res = -1;
debug_safe(1, "Could not send job %s ('%s') to foreground", job_id_buff, j->command_cstr());
wperror(L"tcsetpgrp");
res = -1;
}
}
}
return res;
return res;
}
/** Make sure the fd used by each redirection is not used by a pipe. */
@ -135,15 +135,15 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
replacement_fd = dup(fd_to_free);
if (replacement_fd == -1 && errno != EINTR)
{
debug_safe_int( 1, FD_ERROR, fd_to_free );
wperror( L"dup" );
debug_safe_int(1, FD_ERROR, fd_to_free);
wperror(L"dup");
FATAL_EXIT();
}
}
possible_conflict->param1.pipe_fd[k] = replacement_fd;
}
}
}
}
}
@ -159,152 +159,152 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
\return 0 on sucess, -1 on failiure
*/
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);
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);
int tmp;
int tmp;
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
{
continue;
if (io->io_mode == IO_FD && io->fd == io->param1.old_fd)
{
continue;
}
switch (io->io_mode)
{
case IO_CLOSE:
{
if (close(io->fd))
{
debug_safe_int(0, "Failed to close file descriptor %s", io->fd);
wperror(L"close");
}
break;
}
case IO_FILE:
{
// Here we definitely do not want to set CLO_EXEC because our child needs access
if ((tmp=open(io->filename_cstr,
io->param2.flags, OPEN_MASK))==-1)
{
if ((io->param2.flags & O_EXCL) &&
(errno ==EEXIST))
{
debug_safe(1, NOCLOB_ERROR, io->filename_cstr);
}
else
{
debug_safe(1, FILE_ERROR, io->filename_cstr);
perror("open");
}
return -1;
}
else if (tmp != io->fd)
{
/*
This call will sometimes fail, but that is ok,
this is just a precausion.
*/
close(io->fd);
if (dup2(tmp, io->fd) == -1)
{
debug_safe_int(1, FD_ERROR, io->fd);
perror("dup2");
return -1;
}
exec_close(tmp);
}
break;
}
case IO_FD:
{
/*
This call will sometimes fail, but that is ok,
this is just a precausion.
*/
close(io->fd);
if (dup2(io->param1.old_fd, io->fd) == -1)
{
debug_safe_int(1, FD_ERROR, io->fd);
wperror(L"dup2");
return -1;
}
break;
}
case IO_BUFFER:
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). */
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
/*
debug( 0,
L"%ls %ls on fd %d (%d %d)",
write_pipe?L"write":L"read",
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
io->fd,
io->param1.pipe_fd[0],
io->param1.pipe_fd[1]);
*/
if (dup2(io->param1.pipe_fd[write_pipe_idx], io->fd) != io->fd)
{
debug_safe(1, LOCAL_PIPE_ERROR);
perror("dup2");
return -1;
}
if (io->param1.pipe_fd[0] >= 0)
exec_close(io->param1.pipe_fd[0]);
if (io->param1.pipe_fd[1] >= 0)
exec_close(io->param1.pipe_fd[1]);
break;
}
}
}
switch( io->io_mode )
{
case IO_CLOSE:
{
if( close(io->fd) )
{
debug_safe_int( 0, "Failed to close file descriptor %s", io->fd );
wperror( L"close" );
}
break;
}
case IO_FILE:
{
// Here we definitely do not want to set CLO_EXEC because our child needs access
if( (tmp=open( io->filename_cstr,
io->param2.flags, OPEN_MASK ) )==-1 )
{
if( ( io->param2.flags & O_EXCL ) &&
( errno ==EEXIST ) )
{
debug_safe( 1, NOCLOB_ERROR, io->filename_cstr );
}
else
{
debug_safe( 1, FILE_ERROR, io->filename_cstr );
perror( "open" );
}
return -1;
}
else if( tmp != io->fd)
{
/*
This call will sometimes fail, but that is ok,
this is just a precausion.
*/
close(io->fd);
if(dup2( tmp, io->fd ) == -1 )
{
debug_safe_int( 1, FD_ERROR, io->fd );
perror( "dup2" );
return -1;
}
exec_close( tmp );
}
break;
}
case IO_FD:
{
/*
This call will sometimes fail, but that is ok,
this is just a precausion.
*/
close(io->fd);
if( dup2( io->param1.old_fd, io->fd ) == -1 )
{
debug_safe_int( 1, FD_ERROR, io->fd );
wperror( L"dup2" );
return -1;
}
break;
}
case IO_BUFFER:
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). */
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
/*
debug( 0,
L"%ls %ls on fd %d (%d %d)",
write_pipe?L"write":L"read",
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
io->fd,
io->param1.pipe_fd[0],
io->param1.pipe_fd[1]);
*/
if( dup2( io->param1.pipe_fd[write_pipe_idx], io->fd ) != io->fd )
{
debug_safe( 1, LOCAL_PIPE_ERROR );
perror( "dup2" );
return -1;
}
if (io->param1.pipe_fd[0] >= 0)
exec_close( io->param1.pipe_fd[0]);
if (io->param1.pipe_fd[1] >= 0)
exec_close( io->param1.pipe_fd[1]);
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 )
{
ok = (0 == set_child_group( j, p, 1 ));
}
if( ok )
{
ok = (0 == handle_child_io( j->io ));
if( p != 0 && ! ok )
if (p)
{
exit_without_destructors( 1 );
ok = (0 == set_child_group(j, p, 1));
}
}
/* Set the handling for job control signals back to the default. */
if( ok )
{
signal_reset_handlers();
}
if (ok)
{
ok = (0 == handle_child_io(j->io));
if (p != 0 && ! ok)
{
exit_without_destructors(1);
}
}
/* Remove all signal blocks */
signal_unblock();
/* Set the handling for job control signals back to the default. */
if (ok)
{
signal_reset_handlers();
}
return ok ? 0 : -1;
/* Remove all signal blocks */
signal_unblock();
return ok ? 0 : -1;
}
int g_fork_count = 0;
@ -319,46 +319,47 @@ pid_t execute_fork(bool wait_for_threads_to_die)
{
ASSERT_IS_MAIN_THREAD();
if (wait_for_threads_to_die) {
if (wait_for_threads_to_die)
{
/* Make sure we have no outstanding threads before we fork. This is a pretty sketchy thing to do here, both because exec.cpp shouldn't have to know about iothreads, and because the completion handlers may do unexpected things. */
iothread_drain_all();
}
pid_t pid;
struct timespec pollint;
int i;
pid_t pid;
struct timespec pollint;
int i;
g_fork_count++;
for( i=0; i<FORK_LAPS; i++ )
{
pid = fork();
if( pid >= 0)
for (i=0; i<FORK_LAPS; i++)
{
return pid;
pid = fork();
if (pid >= 0)
{
return pid;
}
if (errno != EAGAIN)
{
break;
}
pollint.tv_sec = 0;
pollint.tv_nsec = FORK_SLEEP_TIME;
/*
Don't sleep on the final lap - sleeping might change the
value of errno, which will break the error reporting below.
*/
if (i != FORK_LAPS-1)
{
nanosleep(&pollint, NULL);
}
}
if( errno != EAGAIN )
{
break;
}
pollint.tv_sec = 0;
pollint.tv_nsec = FORK_SLEEP_TIME;
/*
Don't sleep on the final lap - sleeping might change the
value of errno, which will break the error reporting below.
*/
if( i != FORK_LAPS-1 )
{
nanosleep( &pollint, NULL );
}
}
debug_safe( 0, FORK_ERROR );
wperror (L"fork");
FATAL_EXIT();
debug_safe(0, FORK_ERROR);
wperror(L"fork");
FATAL_EXIT();
return 0;
}
@ -366,11 +367,13 @@ pid_t execute_fork(bool wait_for_threads_to_die)
bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p)
{
/* Initialize the output */
if (posix_spawnattr_init(attr) != 0) {
if (posix_spawnattr_init(attr) != 0)
{
return false;
}
if (posix_spawn_file_actions_init(actions) != 0) {
if (posix_spawn_file_actions_init(actions) != 0)
{
posix_spawnattr_destroy(attr);
return false;
}
@ -389,11 +392,11 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
desired_parent_group_id = j->pgid;
}
/* Set the handling for job control signals back to the default. */
bool reset_signal_handlers = true;
/* Set the handling for job control signals back to the default. */
bool reset_signal_handlers = true;
/* Remove all signal blocks */
bool reset_sigmask = true;
/* Remove all signal blocks */
bool reset_sigmask = true;
/* Set our flags */
short flags = 0;
@ -440,70 +443,71 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
{
const io_data_t *io = j->io.at(idx);
if( io->io_mode == IO_FD && io->fd == io->param1.old_fd )
{
continue;
}
if (io->io_mode == IO_FD && io->fd == io->param1.old_fd)
{
continue;
}
if( io->fd > 2 )
{
/* Make sure the fd used by this redirection is not used by e.g. a pipe. */
if (io->fd > 2)
{
/* Make sure the fd used by this redirection is not used by e.g. a pipe. */
// free_fd(io_chain, io->fd );
// PCA I don't think we need to worry about this. fd redirection is pretty uncommon anyways.
}
}
switch (io->io_mode)
{
case IO_CLOSE:
{
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->fd);
break;
}
case IO_FILE:
{
if (! err)
err = posix_spawn_file_actions_addopen(actions, io->fd, io->filename_cstr, io->param2.flags /* mode */, OPEN_MASK);
break;
}
case IO_FD:
{
if (! err)
err = posix_spawn_file_actions_adddup2(actions, io->param1.old_fd /* from */, io->fd /* to */);
break;
}
case IO_BUFFER:
case IO_PIPE:
{
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
int from_fd = io->param1.pipe_fd[write_pipe_idx];
int to_fd = io->fd;
if (! err)
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
if( write_pipe_idx > 0 )
case IO_CLOSE:
{
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[1]);
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->fd);
break;
}
else
{
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
case IO_FILE:
{
if (! err)
err = posix_spawn_file_actions_addopen(actions, io->fd, io->filename_cstr, io->param2.flags /* mode */, OPEN_MASK);
break;
}
break;
case IO_FD:
{
if (! err)
err = posix_spawn_file_actions_adddup2(actions, io->param1.old_fd /* from */, io->fd /* to */);
break;
}
case IO_BUFFER:
case IO_PIPE:
{
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
int from_fd = io->param1.pipe_fd[write_pipe_idx];
int to_fd = io->fd;
if (! err)
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
if (write_pipe_idx > 0)
{
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[1]);
}
else
{
if (! err)
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
}
break;
}
}
}
/* Clean up on error */
if (err) {
if (err)
{
posix_spawnattr_destroy(attr);
posix_spawn_file_actions_destroy(actions);
}
@ -514,86 +518,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)
{
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:
{
char sz1[128], sz2[128];
char sz1[128], sz2[128];
long arg_max = -1;
long arg_max = -1;
size_t sz = 0;
char **p;
for(p=argv; *p; p++)
{
sz += strlen(*p)+1;
}
size_t sz = 0;
char **p;
for (p=argv; *p; p++)
{
sz += strlen(*p)+1;
}
for(p=envv; *p; p++)
{
sz += strlen(*p)+1;
}
for (p=envv; *p; p++)
{
sz += strlen(*p)+1;
}
format_size_safe(sz1, sz);
arg_max = sysconf( _SC_ARG_MAX );
format_size_safe(sz1, sz);
arg_max = sysconf(_SC_ARG_MAX);
if( arg_max > 0 )
{
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);
}
else
{
debug_safe( 0, "The total size of the argument and environment lists (%s) exceeds the operating system limit.", sz1);
}
if (arg_max > 0)
{
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);
}
else
{
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.");
break;
debug_safe(0, "Try running the command again with fewer arguments.");
break;
}
case ENOEXEC:
{
/* Hope strerror doesn't allocate... */
const char *err = strerror(errno);
debug_safe(0, "exec: %s", err);
/* Hope strerror doesn't allocate... */
const char *err = strerror(errno);
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);
break;
debug_safe(0, "The file '%s' is marked as an executable but could not be run by the operating system.", actual_cmd);
break;
}
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(). */
char interpreter_buff[128] = {}, *interpreter;
interpreter = get_interpreter(actual_cmd, interpreter_buff, sizeof interpreter_buff);
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 );
}
else
{
debug_safe(0, "The file '%s' does not exist or could not be executed.", actual_cmd);
}
break;
/* 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;
interpreter = get_interpreter(actual_cmd, interpreter_buff, sizeof interpreter_buff);
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);
}
else
{
debug_safe(0, "The file '%s' does not exist or could not be executed.", actual_cmd);
}
break;
}
case ENOMEM:
{
debug_safe(0, "Out of memory");
break;
debug_safe(0, "Out of memory");
break;
}
default:
{
/* Hope strerror doesn't allocate... */
const char *err = strerror(errno);
debug_safe(0, "exec: %s", err);
/* Hope strerror doesn't allocate... */
const char *err = strerror(errno);
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);
break;
// debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
break;
}
}
}
}

View file

@ -24,7 +24,7 @@
#endif
#ifndef FISH_USE_POSIX_SPAWN
#define FISH_USE_POSIX_SPAWN HAVE_SPAWN_H
#define FISH_USE_POSIX_SPAWN HAVE_SPAWN_H
#endif
@ -40,7 +40,7 @@
Returns 0 on sucess, -1 on failiure.
*/
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);
/**
Initialize a new child process. This should be called right away
@ -59,7 +59,7 @@ int set_child_group( job_t *j, process_t *p, int print_errors );
signals are always unblocked. On failiure, signal handlers, io
redirections and process group of the process is undefined.
*/
int setup_child_process( job_t *j, process_t *p );
int setup_child_process(job_t *j, process_t *p);
/* Call fork(), optionally waiting until we are no longer multithreaded. If the forked child doesn't do anything that could allocate memory, take a lock, etc. (like call exec), then it's not necessary to wait for threads to die. If the forked child may do those things, it should wait for threads to die.
*/

View file

@ -17,18 +17,18 @@
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];
int printed = snprintf( cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd );
char cmd[ CMD_LEN];
int printed = snprintf(cmd, CMD_LEN, "fish -c '__fish_print_help %s >&%d'", c, fd);
if( printed < CMD_LEN )
{
if( (system( cmd ) == -1) )
if (printed < CMD_LEN)
{
write_loop(2, HELP_ERR, strlen(HELP_ERR));
if ((system(cmd) == -1))
{
write_loop(2, HELP_ERR, strlen(HELP_ERR));
}
}
}
}

View file

@ -10,6 +10,6 @@
Print help message for the specified command
*/
void print_help( const char *cmd, int fd );
void print_help(const char *cmd, int fd);
#endif

1684
proc.cpp

File diff suppressed because it is too large Load diff

281
proc.h
View file

@ -56,41 +56,41 @@
*/
enum
{
/**
A regular external command
*/
EXTERNAL,
/**
A builtin command
*/
INTERNAL_BUILTIN,
/**
A shellscript function
*/
INTERNAL_FUNCTION,
/**
A block of commands
*/
INTERNAL_BLOCK,
/**
The exec builtin
*/
INTERNAL_EXEC,
/**
A buffer
*/
INTERNAL_BUFFER,
/**
A regular external command
*/
EXTERNAL,
/**
A builtin command
*/
INTERNAL_BUILTIN,
/**
A shellscript function
*/
INTERNAL_FUNCTION,
/**
A block of commands
*/
INTERNAL_BLOCK,
/**
The exec builtin
*/
INTERNAL_EXEC,
/**
A buffer
*/
INTERNAL_BUFFER,
}
;
;
enum
{
JOB_CONTROL_ALL,
JOB_CONTROL_INTERACTIVE,
JOB_CONTROL_NONE,
JOB_CONTROL_ALL,
JOB_CONTROL_INTERACTIVE,
JOB_CONTROL_NONE,
}
;
;
/**
A structure representing a single fish process. Contains variables
@ -127,7 +127,7 @@ enum
*/
class process_t
{
private:
private:
null_terminated_array_t<wchar_t> argv_array;
@ -138,84 +138,95 @@ class process_t
process_t(const process_t &rhs);
void operator=(const process_t &rhs);
public:
public:
process_t();
~process_t();
/**
Type of process. Can be one of \c EXTERNAL, \c
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK,
INTERNAL_EXEC, or INTERNAL_BUFFER
*/
int type;
/**
Type of process. Can be one of \c EXTERNAL, \c
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK,
INTERNAL_EXEC, or INTERNAL_BUFFER
*/
int type;
/** Sets argv */
void set_argv(const wcstring_list_t &argv) {
void set_argv(const wcstring_list_t &argv)
{
argv_array.set(argv);
argv0_narrow.set(argv.empty() ? L"" : argv[0]);
}
/** Returns argv */
const wchar_t * const *get_argv(void) const { return argv_array.get(); }
const null_terminated_array_t<wchar_t> &get_argv_array(void) const { return argv_array; }
const wchar_t * const *get_argv(void) const
{
return argv_array.get();
}
const null_terminated_array_t<wchar_t> &get_argv_array(void) const
{
return argv_array;
}
/** Returns argv[idx] */
const wchar_t *argv(size_t idx) const {
const wchar_t *argv(size_t idx) const
{
const wchar_t * const *argv = argv_array.get();
assert(argv != NULL);
return argv[idx];
}
/** Returns argv[0], or NULL */
const wchar_t *argv0(void) const {
const wchar_t *argv0(void) const
{
const wchar_t * const *argv = argv_array.get();
return argv ? argv[0] : NULL;
}
/** Returns argv[0] as a char * */
const char *argv0_cstr(void) const {
const char *argv0_cstr(void) const
{
return argv0_narrow.get();
}
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. */
wcstring actual_cmd;
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. */
wcstring actual_cmd;
/** process ID */
pid_t pid;
/** process ID */
pid_t pid;
/** File descriptor that pipe output should bind to */
int pipe_write_fd;
/** File descriptor that pipe output should bind to */
int pipe_write_fd;
/** File descriptor that the _next_ process pipe input should bind to */
int pipe_read_fd;
/** File descriptor that the _next_ process pipe input should bind to */
int pipe_read_fd;
/** true if process has completed */
volatile int completed;
/** true if process has completed */
volatile int completed;
/** true if process has stopped */
volatile int stopped;
/** true if process has stopped */
volatile int stopped;
/** reported status value */
volatile int status;
/** reported status value */
volatile int status;
/** Special flag to tell the evaluation function for count to print the help information */
int count_help_magic;
/** Special flag to tell the evaluation function for count to print the help information */
int count_help_magic;
/** Next process in pipeline. We own this and we are responsible for deleting it. */
process_t *next;
/** Next process in pipeline. We own this and we are responsible for deleting it. */
process_t *next;
#ifdef HAVE__PROC_SELF_STAT
/** Last time of cpu time check */
struct timeval last_time;
/** Number of jiffies spent in process at last cpu time check */
unsigned long last_jiffies;
/** Last time of cpu time check */
struct timeval last_time;
/** Number of jiffies spent in process at last cpu time check */
unsigned long last_jiffies;
#endif
};
/* Constants for the flag variable in the job struct */
enum {
enum
{
/** true if user was told about stopped job */
JOB_NOTIFIED = 1 << 0,
@ -223,9 +234,9 @@ enum {
JOB_FOREGROUND = 1 << 1,
/**
Whether the specified job is completely constructed,
i.e. completely parsed, and every process in the job has been
forked, etc.
Whether the specified job is completely constructed,
i.e. completely parsed, and every process in the job has been
forked, etc.
*/
JOB_CONSTRUCTED = 1 << 2,
@ -261,12 +272,12 @@ void release_job_id(job_id_t jobid);
class job_t
{
/**
The original command which led to the creation of this
job. It is used for displaying messages about job status
on the terminal.
*/
wcstring command_str;
/**
The original command which led to the creation of this
job. It is used for displaying messages about job status
on the terminal.
*/
wcstring command_str;
/* narrow copy so we don't have to convert after fork */
narrow_string_rep_t command_narrow;
@ -275,62 +286,75 @@ class job_t
job_t(const job_t &rhs);
void operator=(const job_t &);
public:
public:
job_t(job_id_t jobid);
~job_t();
/** Returns whether the command is empty. */
bool command_is_empty() const { return command_str.empty(); }
bool command_is_empty() const
{
return command_str.empty();
}
/** Returns the command as a wchar_t *. */
const wchar_t *command_wcstr() const { return command_str.c_str(); }
const wchar_t *command_wcstr() const
{
return command_str.c_str();
}
/** Returns the command */
const wcstring &command() const { return command_str; }
const wcstring &command() const
{
return command_str;
}
/** Returns the command as a char *. */
const char *command_cstr() const { return command_narrow.get(); }
const char *command_cstr() const
{
return command_narrow.get();
}
/** Sets the command */
void set_command(const wcstring &cmd) {
void set_command(const wcstring &cmd)
{
command_str = 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.
*/
process_t *first_process;
/**
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 group ID for the process group that this job is
running in.
*/
pid_t pgid;
/**
process group ID for the process group that this job is
running in.
*/
pid_t pgid;
/**
The saved terminal modes of this job. This needs to be
saved so that we can restore the terminal to the same
state after temporarily taking control over the terminal
when a job stops.
*/
struct termios tmodes;
/**
The saved terminal modes of this job. This needs to be
saved so that we can restore the terminal to the same
state after temporarily taking control over the terminal
when a job stops.
*/
struct termios tmodes;
/**
The job id of the job. This is a small integer that is a
unique identifier of the job within this shell, and is
used e.g. in process expansion.
*/
const job_id_t job_id;
/**
The job id of the job. This is a small integer that is a
unique identifier of the job within this shell, and is
used e.g. in process expansion.
*/
const job_id_t job_id;
/** List of all IO redirections for this job. */
io_chain_t io;
/** List of all IO redirections for this job. */
io_chain_t io;
/**
Bitset containing information about the job. A combination of the JOB_* constants.
*/
unsigned int flags;
/**
Bitset containing information about the job. A combination of the JOB_* constants.
*/
unsigned int flags;
};
/**
@ -371,16 +395,19 @@ bool job_list_is_empty(void);
/** A class to aid iteration over jobs list.
Note this is used from a signal handler, so it must be careful to not allocate memory.
*/
class job_iterator_t {
class job_iterator_t
{
job_list_t * const job_list;
job_list_t::iterator current, end;
public:
public:
void reset(void);
job_t *next() {
job_t *next()
{
job_t *job = NULL;
if (current != end) {
if (current != end)
{
job = *current;
++current;
}
@ -426,17 +453,17 @@ extern int no_exec;
/**
Add the specified flag to the bitset of flags for the specified job
*/
void job_set_flag( job_t *j, int flag, int set );
void job_set_flag(job_t *j, int flag, int set);
/**
Returns one if the specified flag is set in the specified job, 0 otherwise.
*/
int job_get_flag( const job_t *j, int flag );
int job_get_flag(const job_t *j, int flag);
/**
Sets the status of the last process to exit
*/
void proc_set_last_status( int s );
void proc_set_last_status(int s);
/**
Returns the status of the last process to exit
@ -446,7 +473,7 @@ int proc_get_last_status();
/**
Remove the specified job
*/
void job_free( job_t* j );
void job_free(job_t* j);
/**
Promotes a job to the front of the job list.
@ -473,12 +500,12 @@ job_t *job_get_from_pid(int pid);
/**
Tests if the job is stopped
*/
int job_is_stopped( const job_t *j );
int job_is_stopped(const job_t *j);
/**
Tests if the job has completed, i.e. if the last process of the pipeline has ended.
*/
int job_is_completed( const job_t *j );
int job_is_completed(const job_t *j);
/**
Reassume a (possibly) stopped job. Put job j in the foreground. If
@ -488,7 +515,7 @@ int job_is_completed( const job_t *j );
\param j The job
\param cont Whether the function should wait for the job to complete before returning
*/
void job_continue( job_t *j, int cont );
void job_continue(job_t *j, int cont);
/**
Notify the user about stopped or terminated jobs. Delete terminated
@ -496,21 +523,21 @@ void job_continue( job_t *j, int cont );
\param interactive whether interactive jobs should be reaped as well
*/
int job_reap( bool interactive );
int job_reap(bool interactive);
/**
Signal handler for SIGCHLD. Mark any processes with relevant
information.
*/
void job_handle_signal( int signal, siginfo_t *info, void *con );
void job_handle_signal(int signal, siginfo_t *info, void *con);
/**
Send the specified signal to all processes in the specified job.
*/
int job_signal( job_t *j, int signal );
int job_signal(job_t *j, int signal);
/* Marks a process as failed to execute (and therefore completed) */
void job_mark_process_as_failed( const job_t *job, process_t *p );
void job_mark_process_as_failed(const job_t *job, process_t *p);
#ifdef HAVE__PROC_SELF_STAT
/**
@ -518,7 +545,7 @@ void job_mark_process_as_failed( const job_t *job, process_t *p );
was used by this process. This function is only available on
systems with the procfs file entry 'stat', i.e. Linux.
*/
unsigned long proc_get_jiffies( process_t *p );
unsigned long proc_get_jiffies(process_t *p);
/**
Update process time usage for all processes by calling the
@ -539,7 +566,7 @@ void proc_sanity_check();
Send a process/job exit event notification. This function is a
conveniance wrapper around event_fire().
*/
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status );
void proc_fire_event(const wchar_t *msg, int type, pid_t pid, int status);
/**
Initializations
@ -555,7 +582,7 @@ void proc_destroy();
Set new value for is_interactive flag, saving previous value. If
needed, update signal handlers.
*/
void proc_push_interactive( int value );
void proc_push_interactive(int value);
/**
Set is_interactive flag to the previous value. If needed, update

4135
reader.cpp

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/** \file reader.h
/** \file reader.h
Prototypes for functions for reading data from stdin and passing
to the parser. If stdin is a keyboard, it supplies a killring,
@ -24,12 +24,12 @@ class history_t;
/**
Read commands from \c fd until encountering EOF
*/
int reader_read( int fd, const io_chain_t &io);
int reader_read(int fd, const io_chain_t &io);
/**
Tell the shell that it should exit after the currently running command finishes.
*/
void reader_exit( int do_exit, int force );
void reader_exit(int do_exit, int force);
/**
Check that the reader is in a sane state
@ -53,10 +53,10 @@ const wchar_t *reader_current_filename();
/**
Push a new filename on the stack of read files
\param fn The fileanme to push
*/
void reader_push_current_filename( const wchar_t *fn );
void reader_push_current_filename(const wchar_t *fn);
/**
Pop the current filename from the stack of read files
*/
@ -85,7 +85,7 @@ void reader_repaint_if_needed();
Run the specified command with the correct terminal modes, and
while taking care to perform job notification, set the title, etc.
*/
void reader_run_command( const wchar_t *buff );
void reader_run_command(const wchar_t *buff);
/**
Get the string of character currently entered into the command
@ -103,7 +103,7 @@ history_t *reader_get_history(void);
\param p the cursor position. If \c p is larger than the length of the command line,
the cursor is placed on the last character.
*/
void reader_set_buffer( const wcstring &b, size_t p );
void reader_set_buffer(const wcstring &b, size_t p);
/**
Get the current cursor position in the command line. If interactive
@ -125,9 +125,9 @@ int reader_interrupted();
const wchar_t *reader_readline();
/**
Push a new reader environment.
Push a new reader environment.
*/
void reader_push( const wchar_t *name );
void reader_push(const wchar_t *name);
/**
Return to previous reader environment
@ -135,66 +135,66 @@ void reader_push( const wchar_t *name );
void reader_pop();
/**
Specify function to use for finding possible tab completions. The function must take these arguments:
Specify function to use for finding possible tab completions. The function must take these arguments:
- The command to be completed as a null terminated array of wchar_t
- An array_list_t in which completions will be inserted.
*/
typedef void (*complete_function_t)( const wcstring &, std::vector<completion_t> &, complete_type_t, wcstring_list_t * lst );
void reader_set_complete_function( complete_function_t );
typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> &, complete_type_t, wcstring_list_t * lst);
void reader_set_complete_function(complete_function_t);
/**
The type of a highlight function.
*/
class env_vars_snapshot_t;
typedef void (*highlight_function_t)( const wcstring &, std::vector<int> &, size_t, wcstring_list_t *, const env_vars_snapshot_t &vars );
typedef void (*highlight_function_t)(const wcstring &, std::vector<int> &, size_t, wcstring_list_t *, const env_vars_snapshot_t &vars);
/**
Specify function for syntax highlighting. The function must take these arguments:
- The command to be highlighted as a null terminated array of wchar_t
- The color code of each character as an array of ints
- The cursor position
- An array_list_t used for storing error messages
*/
void reader_set_highlight_function( highlight_function_t );
void reader_set_highlight_function(highlight_function_t);
/**
Specify function for testing if the command buffer contains syntax
errors that must be corrected before returning.
*/
void reader_set_test_function( int (*f)( const wchar_t * ) );
void reader_set_test_function(int (*f)(const wchar_t *));
/**
Specify string of shell commands to be run in order to generate the
prompt.
*/
void reader_set_left_prompt( const wcstring &prompt );
void reader_set_left_prompt(const wcstring &prompt);
/**
Specify string of shell commands to be run in order to generate the
right prompt.
*/
void reader_set_right_prompt( const wcstring &prompt );
void reader_set_right_prompt(const wcstring &prompt);
/** Sets whether autosuggesting is allowed. */
void reader_set_allow_autosuggesting(bool flag);
/**
Returns true if the shell is exiting, 0 otherwise.
Returns true if the shell is exiting, 0 otherwise.
*/
int exit_status();
/**
Replace the current token with the specified string
*/
void reader_replace_current_token( const wchar_t *new_token );
void reader_replace_current_token(const wchar_t *new_token);
/**
The readers interrupt signal handler. Cancels all currently running blocks.
*/
void reader_handle_int( int signal );
void reader_handle_int(int signal);
/**
This function returns true if fish is exiting by force, i.e. because stdin died
@ -205,7 +205,7 @@ int reader_exit_forced();
Test if the given shell command contains errors. Uses parser_test
for testing. Suitable for reader_set_test_function().
*/
int reader_shell_test( const wchar_t *b );
int reader_shell_test(const wchar_t *b);
/**
Test whether the interactive reader is in search mode.

View file

@ -34,43 +34,43 @@ static int insane;
void sanity_lose()
{
debug( 0, _(L"Errors detected, shutting down. Break on sanity_lose() to debug.") );
insane = 1;
debug(0, _(L"Errors detected, shutting down. Break on sanity_lose() to debug."));
insane = 1;
}
int sanity_check()
{
if( !insane )
if( get_is_interactive() )
history_sanity_check();
if( !insane )
reader_sanity_check();
if( !insane )
kill_sanity_check();
if( !insane )
proc_sanity_check();
if (!insane)
if (get_is_interactive())
history_sanity_check();
if (!insane)
reader_sanity_check();
if (!insane)
kill_sanity_check();
if (!insane)
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 )
{
debug( 0, _(L"The pointer '%ls' is invalid"), err );
sanity_lose();
}
if ((0x00000003l & (intptr_t)ptr) != 0)
{
debug(0, _(L"The pointer '%ls' is invalid"), err);
sanity_lose();
}
if((!null_ok) && (ptr==0))
{
debug( 0, _(L"The pointer '%ls' is null"), err );
sanity_lose();
}
if ((!null_ok) && (ptr==0))
{
debug(0, _(L"The pointer '%ls' is null"), err);
sanity_lose();
}
}

View file

@ -24,6 +24,6 @@ int sanity_check();
\param err A description of what the pointer refers to, for use in error messages
\param null_ok Wheter the pointer is allowed to point to 0
*/
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);
#endif

1106
screen.cpp

File diff suppressed because it is too large Load diff

View file

@ -63,36 +63,43 @@ class screen_data_t
{
std::vector<line_t> line_datas;
public:
public:
struct cursor_t {
struct cursor_t
{
int x;
int y;
cursor_t() : x(0), y(0) { }
cursor_t(int a, int b) : x(a), y(b) { }
} cursor;
line_t &add_line(void) {
line_t &add_line(void)
{
line_datas.resize(line_datas.size() + 1);
return line_datas.back();
}
void resize(size_t size) {
void resize(size_t size)
{
line_datas.resize(size);
}
line_t &create_line(size_t idx) {
if (idx >= line_datas.size()) {
line_t &create_line(size_t idx)
{
if (idx >= line_datas.size())
{
line_datas.resize(idx + 1);
}
return line_datas.at(idx);
}
line_t &line(size_t idx) {
line_t &line(size_t idx)
{
return line_datas.at(idx);
}
size_t line_count(void) {
size_t line_count(void)
{
return line_datas.size();
}
};
@ -102,7 +109,7 @@ class screen_data_t
*/
class screen_t
{
public:
public:
/** Constructor */
screen_t();
@ -139,17 +146,17 @@ class screen_t
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
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. */
size_t actual_lines_before_reset;
/**
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.
*/
struct stat prev_buff_1, prev_buff_2, post_buff_1, post_buff_2;
/**
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.
*/
struct stat prev_buff_1, prev_buff_2, post_buff_1, post_buff_2;
};
/**
@ -168,24 +175,24 @@ class screen_t
\param indent the indent to use for the command line
\param cursor_pos where the cursor is
*/
void s_write( screen_t *s,
const wchar_t *left_prompt,
const wchar_t *right_prompt,
const wchar_t *commandline,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos );
void s_write(screen_t *s,
const wchar_t *left_prompt,
const wchar_t *right_prompt,
const wchar_t *commandline,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos);
void s_write( screen_t *s,
const wcstring &left_prompt,
const wcstring &right_prompt,
const wcstring &commandline,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos );
void s_write(screen_t *s,
const wcstring &left_prompt,
const wcstring &right_prompt,
const wcstring &commandline,
size_t explicit_len,
const int *colors,
const int *indent,
size_t cursor_pos);
/**
This function resets the screen buffers internal knowledge about
@ -203,6 +210,6 @@ void s_write( screen_t *s,
resizing, there will be one line of garbage for every repaint,
which will quicly fill the screen.
*/
void s_reset( screen_t *s, bool reset_cursor, bool reset_prompt = true );
void s_reset(screen_t *s, bool reset_cursor, bool reset_prompt = true);
#endif

View file

@ -59,7 +59,7 @@
#define GETOPT_STRING "b:hvocu"
#ifdef _
#undef _
#undef _
#endif
#ifdef USE_GETTEXT
@ -70,74 +70,80 @@
const char *col[]=
{
"black",
"red",
"green",
"brown",
"yellow",
"blue",
"magenta",
"purple",
"cyan",
"white",
"normal"
"black",
"red",
"green",
"brown",
"yellow",
"blue",
"magenta",
"purple",
"cyan",
"white",
"normal"
};
const int col_idx[]=
{
0,
1,
2,
3,
3,
4,
5,
5,
6,
7,
8
0,
1,
2,
3,
3,
4,
5,
5,
6,
7,
8
};
void print_colors()
{
size_t i;
for( i=0; i<COLORS; i++ )
{
printf( "%s\n", col[i] );
}
size_t i;
for (i=0; i<COLORS; i++)
{
printf("%s\n", col[i]);
}
}
static void check_locale_init()
{
static int is_init = 0;
if( is_init )
return;
static int is_init = 0;
if (is_init)
return;
is_init = 1;
setlocale( LC_ALL, "" );
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
textdomain( PACKAGE_NAME );
is_init = 1;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);
}
/* A lot of this code is taken straight from output.cpp; it sure would be nice to factor these together. */
static bool support_term256;
static bool output_get_supports_term256(void) {
static bool output_get_supports_term256(void)
{
return support_term256;
}
static bool term256_support_is_native(void) {
static bool term256_support_is_native(void)
{
/* Return YES if we think the term256 support is "native" as opposed to forced. */
return max_colors == 256;
}
static bool write_color(char *todo, unsigned char idx, bool is_fg) {
static bool write_color(char *todo, unsigned char idx, bool is_fg)
{
bool result = false;
if (idx < 16 || term256_support_is_native()) {
if (idx < 16 || term256_support_is_native())
{
/* Use tparm */
putp( tparm( todo, idx ) );
putp(tparm(todo, idx));
result = true;
} else {
}
else
{
/* We are attempting to bypass the term here. Generate the ANSI escape sequence ourself. */
char stridx[128];
format_long_safe(stridx, (long)idx);
@ -151,225 +157,244 @@ static bool write_color(char *todo, unsigned char idx, bool is_fg) {
return result;
}
static bool write_foreground_color(unsigned char idx) {
if (set_a_foreground && set_a_foreground[0]) {
static bool write_foreground_color(unsigned char idx)
{
if (set_a_foreground && set_a_foreground[0])
{
return write_color(set_a_foreground, idx, true);
} else if (set_foreground && set_foreground[0]) {
}
else if (set_foreground && set_foreground[0])
{
return write_color(set_foreground, idx, true);
} else {
}
else
{
return false;
}
}
static bool write_background_color(unsigned char idx) {
if (set_a_background && set_a_background[0]) {
static bool write_background_color(unsigned char idx)
{
if (set_a_background && set_a_background[0])
{
return write_color(set_a_background, idx, false);
} else if (set_background && set_background[0]) {
}
else if (set_background && set_background[0])
{
return write_color(set_background, idx, false);
} else {
}
else
{
return false;
}
}
static unsigned char index_for_color(rgb_color_t c) {
if (c.is_named() || ! output_get_supports_term256()) {
static unsigned char index_for_color(rgb_color_t c)
{
if (c.is_named() || ! output_get_supports_term256())
{
return c.to_name_index();
} else {
}
else
{
return c.to_term256_index();
}
}
int main( int argc, char **argv )
int main(int argc, char **argv)
{
/* Some code passes variables to set_color that don't exist, like $fish_user_whatever. As a hack, quietly return failure. */
if (argc <= 1)
return EXIT_FAILURE;
char *bgcolor=0;
char *fgcolor=0;
bool bold=false;
bool underline=false;
char *bgcolor=0;
char *fgcolor=0;
bool bold=false;
bool underline=false;
while( 1 )
{
static struct option
long_options[] =
{
{
"background", required_argument, 0, 'b'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"bold", no_argument, 0, 'o'
}
,
{
"underline", no_argument, 0, 'u'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
"print-colors", no_argument, 0, 'c'
}
,
{
0, 0, 0, 0
}
}
;
int opt_index = 0;
int opt = getopt_long( argc,
argv,
GETOPT_STRING,
long_options,
&opt_index );
if( opt == -1 )
break;
switch( opt )
while (1)
{
case 0:
break;
static struct option
long_options[] =
{
{
"background", required_argument, 0, 'b'
}
,
{
"help", no_argument, 0, 'h'
}
,
{
"bold", no_argument, 0, 'o'
}
,
{
"underline", no_argument, 0, 'u'
}
,
{
"version", no_argument, 0, 'v'
}
,
{
"print-colors", no_argument, 0, 'c'
}
,
{
0, 0, 0, 0
}
}
;
case 'b':
bgcolor = optarg;
break;
case 'h':
print_help( argv[0], 1 );
exit(0);
int opt_index = 0;
case 'o':
bold=true;
break;
int opt = getopt_long(argc,
argv,
GETOPT_STRING,
long_options,
&opt_index);
case 'u':
underline=true;
break;
if (opt == -1)
break;
case 'v':
check_locale_init();
fprintf( stderr, _("%s, version %s\n"), SET_COLOR, PACKAGE_VERSION );
exit( 0 );
switch (opt)
{
case 0:
break;
case 'c':
print_colors();
exit(0);
case 'b':
bgcolor = optarg;
break;
case 'h':
print_help(argv[0], 1);
exit(0);
case '?':
return 1;
case 'o':
bold=true;
break;
case 'u':
underline=true;
break;
case 'v':
check_locale_init();
fprintf(stderr, _("%s, version %s\n"), SET_COLOR, PACKAGE_VERSION);
exit(0);
case 'c':
print_colors();
exit(0);
case '?':
return 1;
}
}
}
switch( argc-optind)
{
switch (argc-optind)
{
case 0:
// printf( "no fg\n" );
break;
break;
case 1:
fgcolor=argv[optind];
fgcolor=argv[optind];
// printf( "fg %s\n", fgcolor );
break;
break;
default:
check_locale_init();
printf( _("%s: Too many arguments\n"), SET_COLOR );
return 1;
}
check_locale_init();
printf(_("%s: Too many arguments\n"), SET_COLOR);
return 1;
}
/* Infer term256 support */
char *fish_term256 = getenv("fish_term256");
if (fish_term256) {
if (fish_term256)
{
support_term256 = from_string<bool>(fish_term256);
} else {
}
else
{
const char *term = getenv("TERM");
support_term256 = term && strstr(term, "256color");
}
if( !fgcolor && !bgcolor && !bold && !underline )
{
check_locale_init();
fprintf( stderr, _("%s: Expected an argument\n"), SET_COLOR );
print_help( argv[0], 2 );
return 1;
}
if (!fgcolor && !bgcolor && !bold && !underline)
{
check_locale_init();
fprintf(stderr, _("%s: Expected an argument\n"), SET_COLOR);
print_help(argv[0], 2);
return 1;
}
rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : "");
if( fgcolor && fg.is_none())
{
check_locale_init();
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, fgcolor );
return 1;
}
if (fgcolor && fg.is_none())
{
check_locale_init();
fprintf(stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, fgcolor);
return 1;
}
rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : "");
if( bgcolor && bg.is_none())
{
check_locale_init();
fprintf( stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, bgcolor );
return 1;
}
setupterm( 0, STDOUT_FILENO, 0);
if( bold )
{
if( enter_bold_mode )
putp( enter_bold_mode );
}
if( underline )
{
if( enter_underline_mode )
putp( enter_underline_mode );
}
if( bgcolor )
{
if( bg.is_normal() )
if (bgcolor && bg.is_none())
{
check_locale_init();
fprintf(stderr, _("%s: Unknown color '%s'\n"), SET_COLOR, bgcolor);
return 1;
}
setupterm(0, STDOUT_FILENO, 0);
if (bold)
{
if (enter_bold_mode)
putp(enter_bold_mode);
}
if (underline)
{
if (enter_underline_mode)
putp(enter_underline_mode);
}
if (bgcolor)
{
if (bg.is_normal())
{
write_background_color(0);
putp( tparm(exit_attribute_mode) );
putp(tparm(exit_attribute_mode));
}
}
}
if( fgcolor )
{
if( fg.is_normal() )
if (fgcolor)
{
if (fg.is_normal())
{
write_foreground_color(0);
putp( tparm(exit_attribute_mode) );
}
else
{
putp(tparm(exit_attribute_mode));
}
else
{
write_foreground_color(index_for_color(fg));
}
}
}
if( bgcolor )
{
if( ! bg.is_normal() )
if (bgcolor)
{
if (! bg.is_normal())
{
write_background_color(index_for_color(bg));
}
}
}
if( del_curterm( cur_term ) == ERR )
{
fprintf( stderr, "%s", _("Error while closing terminfo") );
}
if (del_curterm(cur_term) == ERR)
{
fprintf(stderr, "%s", _("Error while closing terminfo"));
}
}

File diff suppressed because it is too large Load diff

View file

@ -12,17 +12,17 @@ The library for various signal related issues
Get the integer signal value representing the specified signal, or
-1 of no signal was found
*/
int wcs2sig( const wchar_t *str );
int wcs2sig(const wchar_t *str);
/**
Get string representation of a signal
*/
const wchar_t *sig2wcs( int sig );
const wchar_t *sig2wcs(int sig);
/**
Returns a description of the specified signal.
*/
const wchar_t *signal_get_desc( int sig );
const wchar_t *signal_get_desc(int sig);
/**
Set all signal handlers to SIG_DFL
@ -40,7 +40,7 @@ void signal_set_handlers();
\param sig The signal to specify the action of
\param do_handle If true fish will catch the specified signal and fire an event, otherwise the default action (SIG_DFL) will be set
*/
void signal_handle( int sig, int do_handle );
void signal_handle(int sig, int do_handle);
/**
Block all signals

File diff suppressed because it is too large Load diff

View file

@ -16,19 +16,19 @@
*/
enum token_type
{
TOK_NONE, /**< Tokenizer not yet constructed */
TOK_ERROR, /**< Error reading token */
TOK_INVALID,/**< Invalid token */
TOK_STRING,/**< String token */
TOK_PIPE,/**< Pipe token */
TOK_END,/**< End token */
TOK_REDIRECT_OUT, /**< redirection token */
TOK_REDIRECT_APPEND,/**< redirection append token */
TOK_REDIRECT_IN,/**< input redirection token */
TOK_REDIRECT_FD,/**< redirection to new fd token */
TOK_REDIRECT_NOCLOB, /**<? redirection token */
TOK_BACKGROUND,/**< send job to bg token */
TOK_COMMENT/**< comment token */
TOK_NONE, /**< Tokenizer not yet constructed */
TOK_ERROR, /**< Error reading token */
TOK_INVALID,/**< Invalid token */
TOK_STRING,/**< String token */
TOK_PIPE,/**< Pipe token */
TOK_END,/**< End token */
TOK_REDIRECT_OUT, /**< redirection token */
TOK_REDIRECT_APPEND,/**< redirection append token */
TOK_REDIRECT_IN,/**< input redirection token */
TOK_REDIRECT_FD,/**< redirection to new fd token */
TOK_REDIRECT_NOCLOB, /**<? redirection token */
TOK_BACKGROUND,/**< send job to bg token */
TOK_COMMENT/**< comment token */
};
/**
@ -36,12 +36,12 @@ enum token_type
*/
enum tokenizer_error
{
TOK_UNTERMINATED_QUOTE,
TOK_UNTERMINATED_SUBSHELL,
TOK_UNTERMINATED_ESCAPE,
TOK_OTHER
TOK_UNTERMINATED_QUOTE,
TOK_UNTERMINATED_SUBSHELL,
TOK_UNTERMINATED_ESCAPE,
TOK_OTHER
}
;
;
/**
@ -67,29 +67,29 @@ enum tokenizer_error
*/
struct tokenizer
{
/** A pointer into the original string, showing where the next token begins */
const wchar_t *buff;
/** A copy of the original string */
const wchar_t *orig_buff;
/** A pointer to the last token*/
wchar_t *last;
/** A pointer into the original string, showing where the next token begins */
const wchar_t *buff;
/** A copy of the original string */
const wchar_t *orig_buff;
/** A pointer to the last token*/
wchar_t *last;
/** Type of last token*/
int last_type;
/** Length of last token*/
size_t last_len;
/** Offset of last token*/
size_t last_pos;
/** Whether there are more tokens*/
bool has_next;
/** Whether incomplete tokens are accepted*/
bool accept_unfinished;
/** Whether commants should be returned*/
bool show_comments;
/** Type of last quote, can be either ' or ".*/
wchar_t last_quote;
/** Last error */
int error;
/** Type of last token*/
int last_type;
/** Length of last token*/
size_t last_len;
/** Offset of last token*/
size_t last_pos;
/** Whether there are more tokens*/
bool has_next;
/** Whether incomplete tokens are accepted*/
bool accept_unfinished;
/** Whether commants should be returned*/
bool show_comments;
/** Type of last quote, can be either ' or ".*/
wchar_t last_quote;
/** Last error */
int error;
/* Whether we are squashing errors */
bool squash_errors;
@ -114,48 +114,48 @@ struct tokenizer
parenthesis, as a valid token. Setting TOK_SHOW_COMMENTS will return comments as tokens
*/
void tok_init( tokenizer *tok, const wchar_t *b, int flags );
void tok_init(tokenizer *tok, const wchar_t *b, int flags);
/**
Jump to the next token.
*/
void tok_next( tokenizer *tok );
void tok_next(tokenizer *tok);
/**
Returns the type of the last token. Must be one of the values in the token_type enum.
*/
int tok_last_type( tokenizer *tok );
int tok_last_type(tokenizer *tok);
/**
Returns the last token string. The string should not be freed by the caller.
*/
wchar_t *tok_last( tokenizer *tok );
wchar_t *tok_last(tokenizer *tok);
/**
Returns the type of quote from the last TOK_QSTRING
*/
wchar_t tok_last_quote( tokenizer *tok );
wchar_t tok_last_quote(tokenizer *tok);
/**
Returns true as long as there are more tokens left
*/
int tok_has_next( tokenizer *tok );
int tok_has_next(tokenizer *tok);
/**
Returns the position of the beginning of the current token in the original string
*/
int tok_get_pos( tokenizer *tok );
int tok_get_pos(tokenizer *tok);
/**
Destroy the tokenizer and free asociated memory
*/
void tok_destroy( tokenizer *tok );
void tok_destroy(tokenizer *tok);
/**
Returns the original string to tokenizer
*/
const wchar_t *tok_string( tokenizer *tok );
const wchar_t *tok_string(tokenizer *tok);
/**
@ -165,22 +165,22 @@ const wchar_t *tok_string( tokenizer *tok );
The string should be freed. After use.
*/
wchar_t *tok_first( const wchar_t *str );
wchar_t *tok_first(const wchar_t *str);
/**
Move tokenizer position
*/
void tok_set_pos( tokenizer *tok, int pos );
void tok_set_pos(tokenizer *tok, int pos);
/**
Returns a string description of the specified token type
*/
const wchar_t *tok_get_desc( int type );
const wchar_t *tok_get_desc(int type);
/**
Get tokenizer error type. Should only be called if tok_last_tope returns TOK_ERROR.
*/
int tok_get_error( tokenizer *tok );
int tok_get_error(tokenizer *tok);
#endif

130
util.cpp
View file

@ -47,81 +47,81 @@
*/
#define SB_MAX_SIZE (128*1024*1024)
int wcsfilecmp( const wchar_t *a, const wchar_t *b )
int wcsfilecmp(const wchar_t *a, const wchar_t *b)
{
CHECK( a, 0 );
CHECK( b, 0 );
CHECK(a, 0);
CHECK(b, 0);
if( *a==0 )
{
if( *b==0)
return 0;
return -1;
}
if( *b==0 )
{
return 1;
}
long secondary_diff=0;
if( iswdigit( *a ) && iswdigit( *b ) )
{
wchar_t *aend, *bend;
long al;
long bl;
long diff;
errno = 0;
al = wcstol( a, &aend, 10 );
bl = wcstol( b, &bend, 10 );
if( errno )
if (*a==0)
{
/*
Huuuuuuuuge numbers - fall back to regular string comparison
*/
return wcscmp( a, b );
if (*b==0)
return 0;
return -1;
}
if (*b==0)
{
return 1;
}
diff = al - bl;
if( diff )
return diff > 0 ? 2 : -2;
secondary_diff = (aend-a) - (bend-b);
a=aend-1;
b=bend-1;
}
else
{
int diff = towlower(*a) - towlower(*b);
if( diff != 0 )
return (diff>0)?2:-2;
secondary_diff = *a-*b;
}
int res = wcsfilecmp( a+1, b+1 );
if( abs(res) < 2 )
{
/*
No primary difference in rest of string.
Use secondary difference on this element if found.
*/
if( secondary_diff )
long secondary_diff=0;
if (iswdigit(*a) && iswdigit(*b))
{
return secondary_diff > 0 ? 1 :-1;
}
}
wchar_t *aend, *bend;
long al;
long bl;
long diff;
return res;
errno = 0;
al = wcstol(a, &aend, 10);
bl = wcstol(b, &bend, 10);
if (errno)
{
/*
Huuuuuuuuge numbers - fall back to regular string comparison
*/
return wcscmp(a, b);
}
diff = al - bl;
if (diff)
return diff > 0 ? 2 : -2;
secondary_diff = (aend-a) - (bend-b);
a=aend-1;
b=bend-1;
}
else
{
int diff = towlower(*a) - towlower(*b);
if (diff != 0)
return (diff>0)?2:-2;
secondary_diff = *a-*b;
}
int res = wcsfilecmp(a+1, b+1);
if (abs(res) < 2)
{
/*
No primary difference in rest of string.
Use secondary difference on this element if found.
*/
if (secondary_diff)
{
return secondary_diff > 0 ? 1 :-1;
}
}
return res;
}
long long get_time()
{
struct timeval time_struct;
gettimeofday( &time_struct, 0 );
return 1000000ll*time_struct.tv_sec+time_struct.tv_usec;
struct timeval time_struct;
gettimeofday(&time_struct, 0);
return 1000000ll*time_struct.tv_sec+time_struct.tv_usec;
}

12
util.h
View file

@ -20,9 +20,9 @@
*/
typedef struct buffer
{
char *buff; /**<data buffer*/
size_t length; /**< Size of buffer */
size_t used; /**< Size of data in buffer */
char *buff; /**<data buffer*/
size_t length; /**< Size of buffer */
size_t used; /**< Size of data in buffer */
}
buffer_t;
@ -30,7 +30,7 @@ buffer_t;
Returns the larger of two ints
*/
template<typename T>
static inline T maxi( T a, T b )
static inline T maxi(T a, T b)
{
return a>b?a:b;
}
@ -39,7 +39,7 @@ static inline T maxi( T a, T b )
Returns the smaller of two ints
*/
template<typename T>
static inline T mini( T a, T b )
static inline T mini(T a, T b)
{
return a<b?a:b;
}
@ -78,7 +78,7 @@ static inline T mini( T a, T b )
internal sort order is not arbitrary, but the names 'file1',
'File2' and 'file3' will still be sorted in the order given above.
*/
int wcsfilecmp( const wchar_t *a, const wchar_t *b );
int wcsfilecmp(const wchar_t *a, const wchar_t *b);
/**
Get the current time in microseconds since Jan 1, 1970

View file

@ -170,7 +170,7 @@ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
@ -180,7 +180,7 @@ static char *posixly_correct;
Use translation functions if available
*/
#ifdef _
#undef _
#undef _
#endif
#ifdef HAVE_TRANSLATE_H
@ -205,18 +205,18 @@ static char *posixly_correct;
/* Avoid depending on library functions or files
whose names are inconsistent. */
char *getenv ();
char *getenv();
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)
return (wchar_t *) str;
str++;
if (*str == chr)
return (wchar_t *) str;
str++;
}
return 0;
return 0;
}
/* If using GCC, we can safely declare strlen this way.
@ -227,7 +227,7 @@ my_index (const wchar_t *str, int chr)
#if !defined (__STDC__) || !__STDC__
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int wcslen (const wchar_t *);
extern int wcslen(const wchar_t *);
#endif /* not __STDC__ */
#endif /* __GNUC__ */
@ -252,93 +252,93 @@ static int last_nonopt;
the new indices of the non-options in ARGV after they are moved. */
static void
exchange (wchar_t **argv)
exchange(wchar_t **argv)
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = woptind;
wchar_t *tem;
int bottom = first_nonopt;
int middle = last_nonopt;
int top = woptind;
wchar_t *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
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)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
}
/* Exclude the moved top segment from further swapping. */
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);
last_nonopt = woptind;
first_nonopt += (woptind - last_nonopt);
last_nonopt = woptind;
}
/* Initialize the internal data when the first call is made. */
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
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
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;
++optstring;
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
@ -398,314 +398,314 @@ _wgetopt_initialize (const wchar_t *optstring)
long-named options. */
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)
optstring = _wgetopt_initialize (optstring);
if (woptind == 0)
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 we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != woptind)
exchange ((wchar_t **) argv);
else if (last_nonopt != woptind)
first_nonopt = woptind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (woptind < argc
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
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. */
/* Check whether the ARGV-element is a long option.
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;
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++)
/* Do nothing. */ ;
/* Test all long options for either exact match
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))
if (ordering == PERMUTE)
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != woptind)
exchange((wchar_t **) argv);
else if (last_nonopt != woptind)
first_nonopt = woptind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (woptind < argc
&& (argv[woptind][0] != '-' || argv[woptind][1] == '\0'))
woptind++;
last_nonopt = woptind;
}
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 '?';
/* 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] == '-'));
}
if (pfound != NULL)
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
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])))))
{
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
wchar_t *nameend;
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++)
/* Do nothing. */ ;
/* Test all long options for either exact match
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)
{
if (argv[woptind - 1][1] == '-')
/* --option */
fwprintf (stderr,
_(L"%ls: Option '--%ls' doesn't allow an argument\n"),
argv[0], pfound->name);
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
/* +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 '?';
{
/* 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;
}
}
}
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;
return c;
}
/* 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
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,
(const struct woption *) 0,
(int *) 0,
0);
return _wgetopt_internal(argc, argv, optstring,
(const struct woption *) 0,
(int *) 0,
0);
}
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
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);
}

220
wgetopt.h
View file

@ -53,154 +53,154 @@ Cambridge, MA 02139, USA. */
extern "C" {
#endif
/** For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
/** For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern wchar_t *woptarg;
extern wchar_t *woptarg;
/** Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
/** Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `woptind' communicates from one call to the next
how much of ARGV has been scanned so far. */
Otherwise, `woptind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int woptind;
extern int woptind;
/** Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
/** Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int wopterr;
extern int wopterr;
/** Set to an option character which was unrecognized. */
/** Set to an option character which was unrecognized. */
extern int woptopt;
extern int woptopt;
/** Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
/** Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an 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
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
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
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct woption
{
/**
long name for switch
*/
struct woption
{
/**
long name for switch
*/
#if defined (__STDC__) && __STDC__
const wchar_t *name;
const wchar_t *name;
#else
wchar_t *name;
wchar_t *name;
#endif
/**
Must be one of no_argument, required_argument and
optional_argument.
/**
Must be one of no_argument, required_argument and
optional_argument.
has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int.
*/
int has_arg;
has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int.
*/
int has_arg;
/**
If non-null, the flag whose value should be set if this switch is encountered
*/
int *flag;
/**
If non-null, the flag whose value should be set if this switch is encountered
*/
int *flag;
/**
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.
*/
int val;
};
/**
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.
*/
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
/* Names for the values of the `has_arg' field of `struct option'. */
/**
Specifies that a switch does not accept an argument
*/
/**
Specifies that a switch does not accept an argument
*/
#define no_argument 0
/**
Specifies that a switch requires an argument
*/
/**
Specifies that a switch requires an argument
*/
#define required_argument 1
/**
Specifies that a switch accepts an optional argument
*/
/**
Specifies that a switch accepts an optional argument
*/
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/**
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);
/**
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);
#else /* not __GNU_LIBRARY__ */
extern int wgetopt ();
extern int wgetopt();
#endif /* __GNU_LIBRARY__ */
/**
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,
const struct woption *longopts, int *longind);
/**
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,
const wchar_t *shortopts,
const struct woption *longopts, int *longind);
/**
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,
const struct woption *longopts, int *longind);
/**
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,
const wchar_t *shortopts,
const struct woption *longopts, int *longind);
/**
Internal only. Users should not call this directly.
*/
extern int _wgetopt_internal (int argc, wchar_t *const *argv,
const wchar_t *shortopts,
const struct woption *longopts, int *longind,
int long_only);
/**
Internal only. Users should not call this directly.
*/
extern int _wgetopt_internal(int argc, wchar_t *const *argv,
const wchar_t *shortopts,
const struct woption *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt ();
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt();
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt_long ();
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt_long();
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt_long_only ();
/**
Get options from argument list. See the glibc manual for information on how to use this function.
*/
extern int wgetopt_long_only();
/**
Internal only. Users should not call this directly.
*/
extern int _wgetopt_internal ();
/**
Internal only. Users should not call this directly.
*/
extern int _wgetopt_internal();
#endif /* __STDC__ */
#ifdef __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -31,16 +31,16 @@ class completion_t;
*/
enum
{
/** Character representing any character except '/' */
ANY_CHAR = WILDCARD_RESERVED,
/** Character representing any character except '/' */
ANY_CHAR = WILDCARD_RESERVED,
/** Character representing any character string not containing '/' (A slash) */
ANY_STRING,
/** Character representing any character string not containing '/' (A slash) */
ANY_STRING,
/** Character representing any character string */
ANY_STRING_RECURSIVE,
/** Character representing any character string */
ANY_STRING_RECURSIVE,
}
;
;
/**
Expand the wildcard by matching against the filesystem.
@ -67,7 +67,7 @@ enum
\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);
/**
Test whether the given wildcard matches the string. Does not perform any I/O.
@ -75,22 +75,22 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_
\param wc The wildcard to test against
\return true if the wildcard matched
*/
bool wildcard_match( const wcstring &str, const wcstring &wc );
bool wildcard_match(const wcstring &str, const wcstring &wc);
/**
Check if the specified string contains wildcards
*/
int wildcard_has( const wchar_t *str, int internal );
int wildcard_has(const wchar_t *str, int internal);
/**
Test wildcard completion
*/
bool wildcard_complete(const wcstring &str,
const wchar_t *wc,
const wchar_t *desc,
wcstring (*desc_func)(const wcstring &),
std::vector<completion_t> &out,
expand_flags_t flags );
const wchar_t *wc,
const wchar_t *desc,
wcstring(*desc_func)(const wcstring &),
std::vector<completion_t> &out,
expand_flags_t flags);
#endif

271
wutil.cpp
View file

@ -68,27 +68,36 @@ void wutil_destroy()
bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name, bool *out_is_dir)
{
struct dirent *d = readdir( dir );
if ( !d ) return false;
struct dirent *d = readdir(dir);
if (!d) return false;
out_name = str2wcstring(d->d_name);
if (out_is_dir) {
if (out_is_dir)
{
/* The caller cares if this is a directory, so check */
bool is_dir;
if (d->d_type == DT_DIR) {
if (d->d_type == DT_DIR)
{
is_dir = true;
} else if (d->d_type == DT_LNK || d->d_type == DT_UNKNOWN) {
}
else if (d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
{
/* We want to treat symlinks to directories as directories. Use stat to resolve it. */
cstring fullpath = wcs2string(dir_path);
fullpath.push_back('/');
fullpath.append(d->d_name);
struct stat buf;
if (stat(fullpath.c_str(), &buf) != 0) {
if (stat(fullpath.c_str(), &buf) != 0)
{
is_dir = false;
} else {
is_dir = !! (S_ISDIR(buf.st_mode));
}
} else {
else
{
is_dir = !!(S_ISDIR(buf.st_mode));
}
}
else
{
is_dir = false;
}
*out_is_dir = is_dir;
@ -98,66 +107,67 @@ bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &ou
bool wreaddir(DIR *dir, std::wstring &out_name)
{
struct dirent *d = readdir( dir );
if ( !d ) return false;
struct dirent *d = readdir(dir);
if (!d) return false;
out_name = str2wcstring(d->d_name);
return true;
}
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 *res;
wchar_t *ret = 0;
char *buffc = (char *)malloc(sz*MAX_UTF8_BYTES);
char *res;
wchar_t *ret = 0;
if( !buffc )
{
errno = ENOMEM;
return 0;
}
res = getcwd( buffc, sz*MAX_UTF8_BYTES );
if( res )
{
if( (size_t)-1 != mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) )
if (!buffc)
{
ret = buff;
errno = ENOMEM;
return 0;
}
}
free( buffc );
res = getcwd(buffc, sz*MAX_UTF8_BYTES);
if (res)
{
if ((size_t)-1 != mbstowcs(buff, buffc, sizeof(wchar_t) * sz))
{
ret = buff;
}
}
return ret;
free(buffc);
return ret;
}
int wchdir( const wcstring &dir )
int wchdir(const wcstring &dir)
{
cstring tmp = wcs2string(dir);
return chdir( tmp.c_str() );
return chdir(tmp.c_str());
}
FILE *wfopen(const wcstring &path, const char *mode)
{
int permissions = 0, options = 0;
size_t idx = 0;
switch (mode[idx++]) {
case 'r':
permissions = O_RDONLY;
break;
case 'w':
permissions = O_WRONLY;
options = O_CREAT | O_TRUNC;
break;
case 'a':
permissions = O_WRONLY;
options = O_CREAT | O_APPEND;
break;
default:
errno = EINVAL;
return NULL;
break;
switch (mode[idx++])
{
case 'r':
permissions = O_RDONLY;
break;
case 'w':
permissions = O_WRONLY;
options = O_CREAT | O_TRUNC;
break;
case 'a':
permissions = O_WRONLY;
options = O_CREAT | O_APPEND;
break;
default:
errno = EINVAL;
return NULL;
break;
}
/* Skip binary */
if (mode[idx] == 'b')
@ -182,13 +192,19 @@ FILE *wfreopen(const wcstring &path, const char *mode, FILE *stream)
return freopen(tmp.c_str(), mode, stream);
}
bool set_cloexec(int fd) {
bool set_cloexec(int fd)
{
int flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) {
if (flags < 0)
{
return false;
} else if (flags & FD_CLOEXEC) {
}
else if (flags & FD_CLOEXEC)
{
return true;
} else {
}
else
{
return fcntl(fd, F_SETFD, flags | FD_CLOEXEC) >= 0;
}
}
@ -199,13 +215,15 @@ static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool
cstring tmp = wcs2string(pathname);
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero */
#ifdef O_CLOEXEC
if (cloexec && O_CLOEXEC) {
if (cloexec && O_CLOEXEC)
{
flags |= O_CLOEXEC;
cloexec = false;
}
#endif
int fd = ::open(tmp.c_str(), flags, mode);
if (cloexec && fd >= 0 && ! set_cloexec(fd)) {
if (cloexec && fd >= 0 && ! set_cloexec(fd))
{
close(fd);
fd = -1;
}
@ -246,7 +264,7 @@ int wstat(const wcstring &file_name, struct stat *buf)
int lwstat(const wcstring &file_name, struct stat *buf)
{
// fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
// fprintf(stderr, "%s\n", __PRETTY_FUNCTION__);
cstring tmp = wcs2string(file_name);
return lstat(tmp.c_str(), buf);
}
@ -266,40 +284,40 @@ int wunlink(const wcstring &file_name)
void wperror(const wcstring &s)
{
int e = errno;
if( !s.empty() )
{
fwprintf( stderr, L"%ls: ", s.c_str() );
}
fwprintf( stderr, L"%s\n", strerror( e ) );
int e = errno;
if (!s.empty())
{
fwprintf(stderr, L"%ls: ", s.c_str());
}
fwprintf(stderr, L"%s\n", strerror(e));
}
#ifdef HAVE_REALPATH_NULL
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
{
cstring tmp = wcs2string(pathname);
char *narrow_res = realpath( tmp.c_str(), 0 );
wchar_t *res;
cstring tmp = wcs2string(pathname);
char *narrow_res = realpath(tmp.c_str(), 0);
wchar_t *res;
if( !narrow_res )
return 0;
if (!narrow_res)
return 0;
if( resolved_path )
{
wchar_t *tmp2 = str2wcs( narrow_res );
wcslcpy( resolved_path, tmp2, PATH_MAX );
free( tmp2 );
res = resolved_path;
}
else
{
res = str2wcs( narrow_res );
}
if (resolved_path)
{
wchar_t *tmp2 = str2wcs(narrow_res);
wcslcpy(resolved_path, tmp2, PATH_MAX);
free(tmp2);
res = resolved_path;
}
else
{
res = str2wcs(narrow_res);
}
free( narrow_res );
free(narrow_res);
return res;
return res;
}
#else
@ -307,53 +325,54 @@ wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
wchar_t *wrealpath(const wcstring &pathname, wchar_t *resolved_path)
{
cstring tmp = wcs2string(pathname);
char narrow_buff[PATH_MAX];
char *narrow_res = realpath( tmp.c_str(), narrow_buff );
wchar_t *res;
char narrow_buff[PATH_MAX];
char *narrow_res = realpath(tmp.c_str(), narrow_buff);
wchar_t *res;
if( !narrow_res )
return 0;
if (!narrow_res)
return 0;
if( resolved_path )
{
wchar_t *tmp2 = str2wcs( narrow_res );
wcslcpy( resolved_path, tmp2, PATH_MAX );
free( tmp2 );
res = resolved_path;
}
else
{
res = str2wcs( narrow_res );
}
return res;
if (resolved_path)
{
wchar_t *tmp2 = str2wcs(narrow_res);
wcslcpy(resolved_path, tmp2, PATH_MAX);
free(tmp2);
res = resolved_path;
}
else
{
res = str2wcs(narrow_res);
}
return res;
}
#endif
wcstring wdirname( const wcstring &path )
wcstring wdirname(const wcstring &path)
{
char *tmp = wcs2str(path.c_str());
char *narrow_res = dirname( tmp );
char *narrow_res = dirname(tmp);
wcstring result = format_string(L"%s", narrow_res);
free(tmp);
return result;
}
wcstring wbasename( const wcstring &path )
wcstring wbasename(const wcstring &path)
{
char *tmp = wcs2str(path.c_str());
char *narrow_res = basename( tmp );
char *narrow_res = basename(tmp);
wcstring result = format_string(L"%s", narrow_res);
free(tmp);
return result;
}
/* Really init wgettext */
static void wgettext_really_init() {
static void wgettext_really_init()
{
pthread_mutex_init(&wgettext_lock, NULL);
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
textdomain( PACKAGE_NAME );
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);
}
/**
@ -365,63 +384,65 @@ static void wgettext_init_if_necessary()
pthread_once(&once, wgettext_really_init);
}
const wchar_t *wgettext( const wchar_t *in )
const wchar_t *wgettext(const wchar_t *in)
{
if( !in )
return in;
if (!in)
return in;
// preserve errno across this since this is often used in printing error messages
int err = errno;
// preserve errno across this since this is often used in printing error messages
int err = errno;
wgettext_init_if_necessary();
wcstring key = in;
wcstring key = in;
scoped_lock lock(wgettext_lock);
wcstring *& val = wgettext_map[key];
if (val == NULL) {
if (val == NULL)
{
cstring mbs_in = wcs2string(key);
char *out = gettext(mbs_in.c_str());
val = new wcstring(format_string(L"%s", out));
}
errno = err;
return val->c_str();
errno = err;
return val->c_str();
}
wcstring wgettext2(const wcstring &in) {
wcstring wgettext2(const wcstring &in)
{
wgettext_init_if_necessary();
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);
return result;
}
const wchar_t *wgetenv( const wcstring &name )
const wchar_t *wgetenv(const wcstring &name)
{
ASSERT_IS_MAIN_THREAD();
cstring name_narrow = wcs2string(name);
char *res_narrow = getenv( name_narrow.c_str() );
static wcstring out;
char *res_narrow = getenv(name_narrow.c_str());
static wcstring out;
if( !res_narrow )
return 0;
if (!res_narrow)
return 0;
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);
return mkdir( name_narrow.c_str(), mode );
cstring name_narrow = wcs2string(name);
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 new_narrow =wcs2string(newv);
return rename( old_narrow.c_str(), new_narrow.c_str() );
cstring new_narrow =wcs2string(newv);
return rename(old_narrow.c_str(), new_narrow.c_str());
}
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base)

16
wutil.h
View file

@ -84,12 +84,12 @@ void wperror(const wcstring &s);
/**
Wide character version of getcwd().
*/
wchar_t *wgetcwd( wchar_t *buff, size_t sz );
wchar_t *wgetcwd(wchar_t *buff, size_t sz);
/**
Wide character version of chdir()
*/
int wchdir( const wcstring &dir );
int wchdir(const wcstring &dir);
/**
Wide character version of realpath function. Just like the GNU
@ -108,12 +108,12 @@ bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &ou
/**
Wide character version of dirname()
*/
std::wstring wdirname( const std::wstring &path);
std::wstring wdirname(const std::wstring &path);
/**
Wide character version of basename()
*/
std::wstring wbasename( const std::wstring &path);
std::wstring wbasename(const std::wstring &path);
/**
Wide character wrapper around the gettext function. For historic
@ -123,23 +123,23 @@ std::wstring wbasename( const std::wstring &path);
wgettext, so that wgettext will be nothing more than a wrapper
around gettext, like all other functions in this file.
*/
const wchar_t *wgettext( const wchar_t *in );
const wchar_t *wgettext(const wchar_t *in);
wcstring wgettext2(const wcstring &in);
/**
Wide character version of getenv
*/
const wchar_t *wgetenv( const wcstring &name );
const wchar_t *wgetenv(const wcstring &name);
/**
Wide character version of mkdir
*/
int wmkdir( const wcstring &dir, int mode );
int wmkdir(const wcstring &dir, int mode);
/**
Wide character version of rename
*/
int wrename( const wcstring &oldName, const wcstring &newName );
int wrename(const wcstring &oldName, const wcstring &newName);
/** Like wcstol(), but fails on a value outside the range of an int */
int fish_wcstoi(const wchar_t *str, wchar_t ** endptr, int base);

File diff suppressed because it is too large Load diff

View file

@ -41,8 +41,8 @@ extern "C" {
#define _XDG_ENTRY3(prefix,func) prefix##_##func
#endif
typedef void (*XdgMimeCallback) (void *user_data);
typedef void (*XdgMimeDestroy) (void *user_data);
typedef void (*XdgMimeCallback)(void *user_data);
typedef void (*XdgMimeDestroy)(void *user_data);
#ifdef XDG_PREFIX
@ -62,29 +62,29 @@ typedef void (*XdgMimeDestroy) (void *user_data);
#define xdg_mime_type_unknown XDG_ENTRY(type_unknown)
#endif
extern const char *xdg_mime_type_unknown;
extern const char *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,
size_t len);
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);
int xdg_mime_is_valid_mime_type (const char *mime_type);
int xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);
int xdg_mime_media_type_equal (const char *mime_a,
const char *mime_b);
int xdg_mime_mime_type_subclass (const char *mime_a,
const char *mime_b);
const char **xdg_mime_get_mime_parents (const char *mime);
const char *xdg_mime_unalias_mime_type (const char *mime);
int xdg_mime_get_max_buffer_extents (void);
void xdg_mime_shutdown (void);
void xdg_mime_dump (void);
int xdg_mime_register_reload_callback (XdgMimeCallback callback,
void *data,
XdgMimeDestroy destroy);
void xdg_mime_remove_callback (int callback_id);
const char *xdg_mime_get_mime_type_for_data(const void *data,
size_t len);
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);
int xdg_mime_is_valid_mime_type(const char *mime_type);
int xdg_mime_mime_type_equal(const char *mime_a,
const char *mime_b);
int xdg_mime_media_type_equal(const char *mime_a,
const char *mime_b);
int xdg_mime_mime_type_subclass(const char *mime_a,
const char *mime_b);
const char **xdg_mime_get_mime_parents(const char *mime);
const char *xdg_mime_unalias_mime_type(const char *mime);
int xdg_mime_get_max_buffer_extents(void);
void xdg_mime_shutdown(void);
void xdg_mime_dump(void);
int xdg_mime_register_reload_callback(XdgMimeCallback callback,
void *data,
XdgMimeDestroy destroy);
void xdg_mime_remove_callback(int callback_id);
#ifdef __cplusplus
}

View file

@ -49,136 +49,136 @@ typedef struct XdgAlias XdgAlias;
struct XdgAlias
{
char *alias;
char *mime_type;
char *alias;
char *mime_type;
};
struct XdgAliasList
{
struct XdgAlias *aliases;
int n_aliases;
struct XdgAlias *aliases;
int n_aliases;
};
XdgAliasList *
_xdg_mime_alias_list_new (void)
_xdg_mime_alias_list_new(void)
{
XdgAliasList *list;
XdgAliasList *list;
list = (XdgAliasList *)malloc (sizeof (XdgAliasList));
list = (XdgAliasList *)malloc(sizeof(XdgAliasList));
list->aliases = NULL;
list->n_aliases = 0;
list->aliases = NULL;
list->n_aliases = 0;
return list;
return list;
}
void
_xdg_mime_alias_list_free (XdgAliasList *list)
_xdg_mime_alias_list_free(XdgAliasList *list)
{
int i;
int i;
if (list->aliases)
if (list->aliases)
{
for (i = 0; i < list->n_aliases; i++)
{
free (list->aliases[i].alias);
free (list->aliases[i].mime_type);
}
free (list->aliases);
for (i = 0; i < list->n_aliases; i++)
{
free(list->aliases[i].alias);
free(list->aliases[i].mime_type);
}
free(list->aliases);
}
free (list);
free(list);
}
static int
alias_entry_cmp (const void *v1, const void *v2)
alias_entry_cmp(const void *v1, const void *v2)
{
return strcmp (((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
return strcmp(((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
}
const char *
_xdg_mime_alias_list_lookup (XdgAliasList *list,
const char *alias)
_xdg_mime_alias_list_lookup(XdgAliasList *list,
const char *alias)
{
XdgAlias *entry;
XdgAlias key;
XdgAlias *entry;
XdgAlias key;
if (list->n_aliases > 0)
if (list->n_aliases > 0)
{
key.alias = (char *)alias;
key.mime_type = 0;
key.alias = (char *)alias;
key.mime_type = 0;
entry = (XdgAlias *)bsearch (&key, list->aliases, list->n_aliases,
sizeof (XdgAlias), alias_entry_cmp);
if (entry)
return entry->mime_type;
entry = (XdgAlias *)bsearch(&key, list->aliases, list->n_aliases,
sizeof(XdgAlias), alias_entry_cmp);
if (entry)
return entry->mime_type;
}
return NULL;
return NULL;
}
void
_xdg_mime_alias_read_from_file (XdgAliasList *list,
const char *file_name)
_xdg_mime_alias_read_from_file(XdgAliasList *list,
const char *file_name)
{
FILE *file;
char line[255];
int alloc;
FILE *file;
char line[255];
int alloc;
/* OK to not use CLO_EXEC here because mimedb is single threaded */
file = fopen (file_name, "r");
/* OK to not use CLO_EXEC here because mimedb is single threaded */
file = fopen(file_name, "r");
if (file == NULL)
return;
if (file == NULL)
return;
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
alloc = list->n_aliases + 16;
list->aliases = (XdgAlias *)realloc (list->aliases, alloc * sizeof (XdgAlias));
while (fgets (line, 255, file) != NULL)
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
alloc = list->n_aliases + 16;
list->aliases = (XdgAlias *)realloc(list->aliases, alloc * sizeof(XdgAlias));
while (fgets(line, 255, file) != NULL)
{
char *sep;
if (line[0] == '#')
continue;
char *sep;
if (line[0] == '#')
continue;
sep = strchr (line, ' ');
if (sep == NULL)
continue;
*(sep++) = '\000';
sep[strlen (sep) -1] = '\000';
if (list->n_aliases == alloc)
{
alloc <<= 1;
list->aliases = (XdgAlias *)realloc (list->aliases,
alloc * sizeof (XdgAlias));
}
list->aliases[list->n_aliases].alias = strdup (line);
list->aliases[list->n_aliases].mime_type = strdup (sep);
list->n_aliases++;
sep = strchr(line, ' ');
if (sep == NULL)
continue;
*(sep++) = '\000';
sep[strlen(sep) -1] = '\000';
if (list->n_aliases == alloc)
{
alloc <<= 1;
list->aliases = (XdgAlias *)realloc(list->aliases,
alloc * sizeof(XdgAlias));
}
list->aliases[list->n_aliases].alias = strdup(line);
list->aliases[list->n_aliases].mime_type = strdup(sep);
list->n_aliases++;
}
list->aliases = (XdgAlias *)realloc (list->aliases,
list->n_aliases * sizeof (XdgAlias));
list->aliases = (XdgAlias *)realloc(list->aliases,
list->n_aliases * sizeof(XdgAlias));
fclose (file);
fclose(file);
if (list->n_aliases > 1)
qsort (list->aliases, list->n_aliases,
sizeof (XdgAlias), alias_entry_cmp);
if (list->n_aliases > 1)
qsort(list->aliases, list->n_aliases,
sizeof(XdgAlias), alias_entry_cmp);
}
void
_xdg_mime_alias_list_dump (XdgAliasList *list)
_xdg_mime_alias_list_dump(XdgAliasList *list)
{
int i;
int i;
if (list->aliases)
if (list->aliases)
{
for (i = 0; i < list->n_aliases; i++)
{
printf ("%s %s\n",
list->aliases[i].alias,
list->aliases[i].mime_type);
}
for (i = 0; i < list->n_aliases; i++)
{
printf("%s %s\n",
list->aliases[i].alias,
list->aliases[i].mime_type);
}
}
}

View file

@ -39,12 +39,12 @@ typedef struct XdgAliasList XdgAliasList;
#define _xdg_mime_alias_list_lookup XDG_ENTRY(alias_list_lookup)
#endif
void _xdg_mime_alias_read_from_file (XdgAliasList *list,
const char *file_name);
XdgAliasList *_xdg_mime_alias_list_new (void);
void _xdg_mime_alias_list_free (XdgAliasList *list);
const char *_xdg_mime_alias_list_lookup (XdgAliasList *list,
const char *alias);
void _xdg_mime_alias_list_dump (XdgAliasList *list);
void _xdg_mime_alias_read_from_file(XdgAliasList *list,
const char *file_name);
XdgAliasList *_xdg_mime_alias_list_new(void);
void _xdg_mime_alias_list_free(XdgAliasList *list);
const char *_xdg_mime_alias_list_lookup(XdgAliasList *list,
const char *alias);
void _xdg_mime_alias_list_dump(XdgAliasList *list);
#endif /* __XDG_MIME_ALIAS_H__ */

View file

@ -50,97 +50,97 @@ typedef struct XdgGlobList XdgGlobList;
struct XdgGlobHashNode
{
xdg_unichar_t character;
const char *mime_type;
XdgGlobHashNode *next;
XdgGlobHashNode *child;
xdg_unichar_t character;
const char *mime_type;
XdgGlobHashNode *next;
XdgGlobHashNode *child;
};
struct XdgGlobList
{
const char *data;
const char *mime_type;
XdgGlobList *next;
const char *data;
const char *mime_type;
XdgGlobList *next;
};
struct XdgGlobHash
{
XdgGlobList *literal_list;
XdgGlobHashNode *simple_node;
XdgGlobList *full_list;
XdgGlobList *literal_list;
XdgGlobHashNode *simple_node;
XdgGlobList *full_list;
};
/* XdgGlobList
*/
static XdgGlobList *
_xdg_glob_list_new (void)
_xdg_glob_list_new(void)
{
XdgGlobList *new_element;
XdgGlobList *new_element;
new_element = (XdgGlobList *)calloc (1, sizeof (XdgGlobList));
new_element = (XdgGlobList *)calloc(1, sizeof(XdgGlobList));
return new_element;
return new_element;
}
/* Frees glob_list and all of it's children */
static void
_xdg_glob_list_free (XdgGlobList *glob_list)
_xdg_glob_list_free(XdgGlobList *glob_list)
{
XdgGlobList *ptr, *next;
XdgGlobList *ptr, *next;
ptr = glob_list;
ptr = glob_list;
while (ptr != NULL)
while (ptr != NULL)
{
next = ptr->next;
next = ptr->next;
if (ptr->data)
free ((void *) ptr->data);
if (ptr->mime_type)
free ((void *) ptr->mime_type);
free (ptr);
if (ptr->data)
free((void *) ptr->data);
if (ptr->mime_type)
free((void *) ptr->mime_type);
free(ptr);
ptr = next;
ptr = next;
}
}
static XdgGlobList *
_xdg_glob_list_append (XdgGlobList *glob_list,
void *data,
const char *mime_type)
_xdg_glob_list_append(XdgGlobList *glob_list,
void *data,
const char *mime_type)
{
XdgGlobList *new_element;
XdgGlobList *tmp_element;
XdgGlobList *new_element;
XdgGlobList *tmp_element;
new_element = _xdg_glob_list_new ();
new_element->data = (const char *)data;
new_element->mime_type = mime_type;
if (glob_list == NULL)
return new_element;
new_element = _xdg_glob_list_new();
new_element->data = (const char *)data;
new_element->mime_type = mime_type;
if (glob_list == NULL)
return new_element;
tmp_element = glob_list;
while (tmp_element->next != NULL)
tmp_element = tmp_element->next;
tmp_element = glob_list;
while (tmp_element->next != NULL)
tmp_element = tmp_element->next;
tmp_element->next = new_element;
tmp_element->next = new_element;
return glob_list;
return glob_list;
}
#if 0
static XdgGlobList *
_xdg_glob_list_prepend (XdgGlobList *glob_list,
void *data,
const char *mime_type)
_xdg_glob_list_prepend(XdgGlobList *glob_list,
void *data,
const char *mime_type)
{
XdgGlobList *new_element;
XdgGlobList *new_element;
new_element = _xdg_glob_list_new ();
new_element->data = data;
new_element->next = glob_list;
new_element->mime_type = mime_type;
new_element = _xdg_glob_list_new();
new_element->data = data;
new_element->next = glob_list;
new_element->mime_type = mime_type;
return new_element;
return new_element;
}
#endif
@ -148,174 +148,174 @@ _xdg_glob_list_prepend (XdgGlobList *glob_list,
*/
static XdgGlobHashNode *
_xdg_glob_hash_node_new (void)
_xdg_glob_hash_node_new(void)
{
XdgGlobHashNode *glob_hash_node;
XdgGlobHashNode *glob_hash_node;
glob_hash_node = (XdgGlobHashNode *)calloc (1, sizeof (XdgGlobHashNode));
glob_hash_node = (XdgGlobHashNode *)calloc(1, sizeof(XdgGlobHashNode));
return glob_hash_node;
return glob_hash_node;
}
static void
_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
int depth)
_xdg_glob_hash_node_dump(XdgGlobHashNode *glob_hash_node,
int depth)
{
int i;
for (i = 0; i < depth; i++)
printf (" ");
int i;
for (i = 0; i < depth; i++)
printf(" ");
printf ("%c", (char)glob_hash_node->character);
if (glob_hash_node->mime_type)
printf (" - %s\n", glob_hash_node->mime_type);
else
printf ("\n");
if (glob_hash_node->child)
_xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
if (glob_hash_node->next)
_xdg_glob_hash_node_dump (glob_hash_node->next, depth);
printf("%c", (char)glob_hash_node->character);
if (glob_hash_node->mime_type)
printf(" - %s\n", glob_hash_node->mime_type);
else
printf("\n");
if (glob_hash_node->child)
_xdg_glob_hash_node_dump(glob_hash_node->child, depth + 1);
if (glob_hash_node->next)
_xdg_glob_hash_node_dump(glob_hash_node->next, depth);
}
static XdgGlobHashNode *
_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
const char *text,
const char *mime_type)
_xdg_glob_hash_insert_text(XdgGlobHashNode *glob_hash_node,
const char *text,
const char *mime_type)
{
XdgGlobHashNode *node;
xdg_unichar_t character;
XdgGlobHashNode *node;
xdg_unichar_t character;
character = _xdg_utf8_to_ucs4 (text);
character = _xdg_utf8_to_ucs4(text);
if ((glob_hash_node == NULL) ||
(character < glob_hash_node->character))
if ((glob_hash_node == NULL) ||
(character < glob_hash_node->character))
{
node = _xdg_glob_hash_node_new ();
node->character = character;
node->next = glob_hash_node;
glob_hash_node = node;
}
else if (character == glob_hash_node->character)
{
node = glob_hash_node;
}
else
{
XdgGlobHashNode *prev_node;
int found_node = FALSE;
/* Look for the first character of text in glob_hash_node, and insert it if we
* have to.*/
prev_node = glob_hash_node;
node = prev_node->next;
while (node != NULL)
{
if (character < node->character)
{
node = _xdg_glob_hash_node_new ();
node = _xdg_glob_hash_node_new();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
found_node = TRUE;
break;
}
else if (character == node->character)
{
found_node = TRUE;
break;
}
prev_node = node;
node = node->next;
}
if (! found_node)
{
node = _xdg_glob_hash_node_new ();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
}
node->next = glob_hash_node;
glob_hash_node = node;
}
text = _xdg_utf8_next_char (text);
if (*text == '\000')
else if (character == glob_hash_node->character)
{
node->mime_type = mime_type;
node = glob_hash_node;
}
else
else
{
node->child = _xdg_glob_hash_insert_text (node->child, text, mime_type);
XdgGlobHashNode *prev_node;
int found_node = FALSE;
/* Look for the first character of text in glob_hash_node, and insert it if we
* have to.*/
prev_node = glob_hash_node;
node = prev_node->next;
while (node != NULL)
{
if (character < node->character)
{
node = _xdg_glob_hash_node_new();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
found_node = TRUE;
break;
}
else if (character == node->character)
{
found_node = TRUE;
break;
}
prev_node = node;
node = node->next;
}
if (! found_node)
{
node = _xdg_glob_hash_node_new();
node->character = character;
node->next = prev_node->next;
prev_node->next = node;
}
}
return glob_hash_node;
text = _xdg_utf8_next_char(text);
if (*text == '\000')
{
node->mime_type = mime_type;
}
else
{
node->child = _xdg_glob_hash_insert_text(node->child, text, mime_type);
}
return glob_hash_node;
}
static const char *
_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
const char *file_name,
int ignore_case)
_xdg_glob_hash_node_lookup_file_name(XdgGlobHashNode *glob_hash_node,
const char *file_name,
int ignore_case)
{
XdgGlobHashNode *node;
xdg_unichar_t character;
XdgGlobHashNode *node;
xdg_unichar_t character;
if (glob_hash_node == NULL)
return NULL;
if (glob_hash_node == NULL)
return NULL;
character = _xdg_utf8_to_ucs4 (file_name);
if (ignore_case)
character = _xdg_ucs4_to_lower(character);
character = _xdg_utf8_to_ucs4(file_name);
if (ignore_case)
character = _xdg_ucs4_to_lower(character);
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)
{
file_name = _xdg_utf8_next_char (file_name);
if (*file_name == '\000')
return node->mime_type;
else
return _xdg_glob_hash_node_lookup_file_name (node->child,
file_name,
ignore_case);
}
if (character == node->character)
{
file_name = _xdg_utf8_next_char(file_name);
if (*file_name == '\000')
return node->mime_type;
else
return _xdg_glob_hash_node_lookup_file_name(node->child,
file_name,
ignore_case);
}
}
return NULL;
return NULL;
}
const char *
_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
const char *file_name)
_xdg_glob_hash_lookup_file_name(XdgGlobHash *glob_hash,
const char *file_name)
{
XdgGlobList *list;
const char *mime_type;
const char *ptr;
/* First, check the literals */
XdgGlobList *list;
const char *mime_type;
const char *ptr;
/* First, check the literals */
assert (file_name != NULL);
assert(file_name != NULL);
for (list = glob_hash->literal_list; list; list = list->next)
if (strcmp ((const char *)list->data, file_name) == 0)
return list->mime_type;
for (list = glob_hash->literal_list; list; list = list->next)
if (strcmp((const char *)list->data, file_name) == 0)
return list->mime_type;
ptr = strchr (file_name, '.');
while (ptr != NULL)
ptr = strchr(file_name, '.');
while (ptr != NULL)
{
mime_type = (_xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, FALSE));
if (mime_type != NULL)
return mime_type;
mime_type = (_xdg_glob_hash_node_lookup_file_name(glob_hash->simple_node, ptr, FALSE));
if (mime_type != NULL)
return mime_type;
mime_type = (_xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, TRUE));
if (mime_type != NULL)
return mime_type;
mime_type = (_xdg_glob_hash_node_lookup_file_name(glob_hash->simple_node, ptr, TRUE));
if (mime_type != NULL)
return mime_type;
ptr = strchr (ptr+1, '.');
ptr = strchr(ptr+1, '.');
}
/* FIXME: Not UTF-8 safe */
for (list = glob_hash->full_list; list; list = list->next)
if (fnmatch ((const char *)list->data, file_name, 0) == 0)
return list->mime_type;
/* FIXME: Not UTF-8 safe */
for (list = glob_hash->full_list; list; list = list->next)
if (fnmatch((const char *)list->data, file_name, 0) == 0)
return list->mime_type;
return NULL;
return NULL;
}
@ -324,150 +324,150 @@ _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
*/
XdgGlobHash *
_xdg_glob_hash_new (void)
_xdg_glob_hash_new(void)
{
XdgGlobHash *glob_hash;
XdgGlobHash *glob_hash;
glob_hash = (XdgGlobHash *)calloc (1, sizeof (XdgGlobHash));
glob_hash = (XdgGlobHash *)calloc(1, sizeof(XdgGlobHash));
return glob_hash;
return glob_hash;
}
static void
_xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
_xdg_glob_hash_free_nodes(XdgGlobHashNode *node)
{
if (node)
if (node)
{
if (node->child)
_xdg_glob_hash_free_nodes (node->child);
if (node->next)
_xdg_glob_hash_free_nodes (node->next);
if (node->mime_type)
free ((void *) node->mime_type);
free (node);
if (node->child)
_xdg_glob_hash_free_nodes(node->child);
if (node->next)
_xdg_glob_hash_free_nodes(node->next);
if (node->mime_type)
free((void *) node->mime_type);
free(node);
}
}
void
_xdg_glob_hash_free (XdgGlobHash *glob_hash)
_xdg_glob_hash_free(XdgGlobHash *glob_hash)
{
_xdg_glob_list_free (glob_hash->literal_list);
_xdg_glob_list_free (glob_hash->full_list);
_xdg_glob_hash_free_nodes (glob_hash->simple_node);
free (glob_hash);
_xdg_glob_list_free(glob_hash->literal_list);
_xdg_glob_list_free(glob_hash->full_list);
_xdg_glob_hash_free_nodes(glob_hash->simple_node);
free(glob_hash);
}
XdgGlobType
_xdg_glob_determine_type (const char *glob)
_xdg_glob_determine_type(const char *glob)
{
const char *ptr;
int maybe_in_simple_glob = FALSE;
int first_char = TRUE;
const char *ptr;
int maybe_in_simple_glob = FALSE;
int first_char = TRUE;
ptr = glob;
ptr = glob;
while (*ptr != '\000')
while (*ptr != '\000')
{
if (*ptr == '*' && first_char)
maybe_in_simple_glob = TRUE;
else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
return XDG_GLOB_FULL;
if (*ptr == '*' && first_char)
maybe_in_simple_glob = TRUE;
else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
return XDG_GLOB_FULL;
first_char = FALSE;
ptr = _xdg_utf8_next_char (ptr);
first_char = FALSE;
ptr = _xdg_utf8_next_char(ptr);
}
if (maybe_in_simple_glob)
return XDG_GLOB_SIMPLE;
else
return XDG_GLOB_LITERAL;
if (maybe_in_simple_glob)
return XDG_GLOB_SIMPLE;
else
return XDG_GLOB_LITERAL;
}
/* glob must be valid UTF-8 */
void
_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type)
_xdg_glob_hash_append_glob(XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type)
{
XdgGlobType type;
XdgGlobType type;
assert (glob_hash != NULL);
assert (glob != NULL);
assert(glob_hash != NULL);
assert(glob != NULL);
type = _xdg_glob_determine_type (glob);
type = _xdg_glob_determine_type(glob);
switch (type)
switch (type)
{
case XDG_GLOB_LITERAL:
glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type));
break;
glob_hash->literal_list = _xdg_glob_list_append(glob_hash->literal_list, strdup(glob), strdup(mime_type));
break;
case XDG_GLOB_SIMPLE:
glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, strdup (mime_type));
break;
glob_hash->simple_node = _xdg_glob_hash_insert_text(glob_hash->simple_node, glob + 1, strdup(mime_type));
break;
case XDG_GLOB_FULL:
glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type));
break;
glob_hash->full_list = _xdg_glob_list_append(glob_hash->full_list, strdup(glob), strdup(mime_type));
break;
}
}
void
_xdg_glob_hash_dump (XdgGlobHash *glob_hash)
_xdg_glob_hash_dump(XdgGlobHash *glob_hash)
{
XdgGlobList *list;
printf ("LITERAL STRINGS\n");
if (glob_hash->literal_list == NULL)
XdgGlobList *list;
printf("LITERAL STRINGS\n");
if (glob_hash->literal_list == NULL)
{
printf (" None\n");
printf(" None\n");
}
else
else
{
for (list = glob_hash->literal_list; list; list = list->next)
printf (" %s - %s\n", (char *)list->data, list->mime_type);
for (list = glob_hash->literal_list; list; list = list->next)
printf(" %s - %s\n", (char *)list->data, list->mime_type);
}
printf ("\nSIMPLE GLOBS\n");
_xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
printf("\nSIMPLE GLOBS\n");
_xdg_glob_hash_node_dump(glob_hash->simple_node, 4);
printf ("\nFULL GLOBS\n");
if (glob_hash->full_list == NULL)
printf("\nFULL GLOBS\n");
if (glob_hash->full_list == NULL)
{
printf (" None\n");
printf(" None\n");
}
else
else
{
for (list = glob_hash->full_list; list; list = list->next)
printf (" %s - %s\n", (char *)list->data, list->mime_type);
for (list = glob_hash->full_list; list; list = list->next)
printf(" %s - %s\n", (char *)list->data, list->mime_type);
}
}
void
_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
const char *file_name)
_xdg_mime_glob_read_from_file(XdgGlobHash *glob_hash,
const char *file_name)
{
FILE *glob_file;
char line[255];
FILE *glob_file;
char line[255];
/* OK to not use CLO_EXEC here because mimedb is single threaded */
glob_file = fopen (file_name, "r");
/* OK to not use CLO_EXEC here because mimedb is single threaded */
glob_file = fopen(file_name, "r");
if (glob_file == NULL)
return;
if (glob_file == NULL)
return;
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
while (fgets (line, 255, glob_file) != NULL)
/* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
* Blah */
while (fgets(line, 255, glob_file) != NULL)
{
char *colon;
if (line[0] == '#')
continue;
char *colon;
if (line[0] == '#')
continue;
colon = strchr (line, ':');
if (colon == NULL)
continue;
*(colon++) = '\000';
colon[strlen (colon) -1] = '\000';
_xdg_glob_hash_append_glob (glob_hash, colon, line);
colon = strchr(line, ':');
if (colon == NULL)
continue;
*(colon++) = '\000';
colon[strlen(colon) -1] = '\000';
_xdg_glob_hash_append_glob(glob_hash, colon, line);
}
fclose (glob_file);
fclose(glob_file);
}

View file

@ -34,9 +34,9 @@ typedef struct XdgGlobHash XdgGlobHash;
typedef enum
{
XDG_GLOB_LITERAL, /* Makefile */
XDG_GLOB_SIMPLE, /* *.gif */
XDG_GLOB_FULL /* x*.[ch] */
XDG_GLOB_LITERAL, /* Makefile */
XDG_GLOB_SIMPLE, /* *.gif */
XDG_GLOB_FULL /* x*.[ch] */
} XdgGlobType;
@ -50,16 +50,16 @@ typedef enum
#define _xdg_glob_hash_dump XDG_ENTRY(hash_dump)
#endif
void _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
const char *file_name);
XdgGlobHash *_xdg_glob_hash_new (void);
void _xdg_glob_hash_free (XdgGlobHash *glob_hash);
const char *_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
const char *text);
void _xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type);
XdgGlobType _xdg_glob_determine_type (const char *glob);
void _xdg_glob_hash_dump (XdgGlobHash *glob_hash);
void _xdg_mime_glob_read_from_file(XdgGlobHash *glob_hash,
const char *file_name);
XdgGlobHash *_xdg_glob_hash_new(void);
void _xdg_glob_hash_free(XdgGlobHash *glob_hash);
const char *_xdg_glob_hash_lookup_file_name(XdgGlobHash *glob_hash,
const char *text);
void _xdg_glob_hash_append_glob(XdgGlobHash *glob_hash,
const char *glob,
const char *mime_type);
XdgGlobType _xdg_glob_determine_type(const char *glob);
void _xdg_glob_hash_dump(XdgGlobHash *glob_hash);
#endif /* __XDG_MIME_GLOB_H__ */

View file

@ -41,15 +41,16 @@
#define TRUE (!FALSE)
#endif
static const char _xdg_utf8_skip_data[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
static const char _xdg_utf8_skip_data[256] =
{
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
@ -60,95 +61,95 @@ const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
xdg_unichar_t
_xdg_utf8_to_ucs4(const char *source)
{
xdg_unichar_t ucs32;
if( ! ( *source & 0x80 ) )
xdg_unichar_t ucs32;
if (!(*source & 0x80))
{
ucs32 = *source;
ucs32 = *source;
}
else
{
int bytelength = 0;
xdg_unichar_t result;
if ( ! (*source & 0x40) )
{
ucs32 = *source;
}
else
{
if ( ! (*source & 0x20) )
{
result = *source++ & 0x1F;
bytelength = 2;
}
else if ( ! (*source & 0x10) )
{
result = *source++ & 0x0F;
bytelength = 3;
}
else if ( ! (*source & 0x08) )
{
result = *source++ & 0x07;
bytelength = 4;
}
else if ( ! (*source & 0x04) )
{
result = *source++ & 0x03;
bytelength = 5;
}
else if ( ! (*source & 0x02) )
{
result = *source++ & 0x01;
bytelength = 6;
}
else
{
result = *source++;
bytelength = 1;
}
{
int bytelength = 0;
xdg_unichar_t result;
if (!(*source & 0x40))
{
ucs32 = *source;
}
else
{
if (!(*source & 0x20))
{
result = *source++ & 0x1F;
bytelength = 2;
}
else if (!(*source & 0x10))
{
result = *source++ & 0x0F;
bytelength = 3;
}
else if (!(*source & 0x08))
{
result = *source++ & 0x07;
bytelength = 4;
}
else if (!(*source & 0x04))
{
result = *source++ & 0x03;
bytelength = 5;
}
else if (!(*source & 0x02))
{
result = *source++ & 0x01;
bytelength = 6;
}
else
{
result = *source++;
bytelength = 1;
}
for ( bytelength --; bytelength > 0; bytelength -- )
{
result <<= 6;
result |= *source++ & 0x3F;
}
ucs32 = result;
}
for (bytelength --; bytelength > 0; bytelength --)
{
result <<= 6;
result |= *source++ & 0x3F;
}
ucs32 = result;
}
}
return ucs32;
return ucs32;
}
/* hullo. this is great code. don't rewrite it */
xdg_unichar_t
_xdg_ucs4_to_lower (xdg_unichar_t source)
_xdg_ucs4_to_lower(xdg_unichar_t source)
{
/* FIXME: Do a real to_upper sometime */
/* CaseFolding-3.2.0.txt has a table of rules. */
if ((source & 0xFF) == source)
return (xdg_unichar_t) tolower ((unsigned char) source);
return source;
/* FIXME: Do a real to_upper sometime */
/* CaseFolding-3.2.0.txt has a table of rules. */
if ((source & 0xFF) == source)
return (xdg_unichar_t) tolower((unsigned char) source);
return source;
}
int
_xdg_utf8_validate (const char *source)
_xdg_utf8_validate(const char *source)
{
/* FIXME: actually write */
return TRUE;
/* FIXME: actually write */
return TRUE;
}
const char *
_xdg_get_base_name (const char *file_name)
_xdg_get_base_name(const char *file_name)
{
const char *base_name;
const char *base_name;
if (file_name == NULL)
return NULL;
if (file_name == NULL)
return NULL;
base_name = strrchr (file_name, '/');
base_name = strrchr(file_name, '/');
if (base_name == NULL)
return file_name;
else
return base_name + 1;
if (base_name == NULL)
return file_name;
else
return base_name + 1;
}

View file

@ -65,9 +65,9 @@ extern const char *const _xdg_utf8_skip;
#define _xdg_utf8_next_char(p) (char *)((p) + _xdg_utf8_skip[*(unsigned char *)(p)])
#define _xdg_utf8_char_size(p) (int) (_xdg_utf8_skip[*(unsigned char *)(p)])
xdg_unichar_t _xdg_utf8_to_ucs4 (const char *source);
xdg_unichar_t _xdg_ucs4_to_lower (xdg_unichar_t source);
int _xdg_utf8_validate (const char *source);
const char *_xdg_get_base_name (const char *file_name);
xdg_unichar_t _xdg_utf8_to_ucs4(const char *source);
xdg_unichar_t _xdg_ucs4_to_lower(xdg_unichar_t source);
int _xdg_utf8_validate(const char *source);
const char *_xdg_get_base_name(const char *file_name);
#endif /* __XDG_MIME_INT_H__ */

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more