Beispiel #1
0
static wcstring path_create_data() {
    bool done = false;
    wcstring res;

    const env_var_t xdg_dir = env_get_string(L"XDG_DATA_HOME");
    if (!xdg_dir.missing()) {
        res = xdg_dir + L"/fish";
        if (!create_directory(res)) {
            done = true;
        }
    } else {
        const env_var_t home = env_get_string(L"HOME");
        if (!home.missing()) {
            res = home + L"/.local/share/fish";
            if (!create_directory(res)) {
                done = true;
            }
        }
    }

    if (!done) {
        res.clear();

        debug(0, _(L"Unable to create a data directory for fish. Your history will not be saved. "
                   L"Please set the $XDG_DATA_HOME variable to a directory where the current user "
                   L"has write access."));
    }
    return res;
}
Beispiel #2
0
static wcstring path_create_config() {
    bool done = false;
    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)) {
            done = true;
        }
    } else {
        const env_var_t home = env_get_string(L"HOME");
        if (!home.missing()) {
            res = home + L"/.config/fish";
            if (!create_directory(res)) {
                done = true;
            }
        }
    }

    if (!done) {
        res.clear();

        debug(0, _(L"Unable to create a configuration directory for fish. Your personal settings "
                   L"will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory "
                   L"where the current user has write access."));
    }
    return res;
}
Beispiel #3
0
/**
   Set up default values for various variables if not defined.
 */
static void env_set_defaults()
{

	if( env_get_string(L"USER").missing() )
	{
		struct passwd *pw = getpwuid( getuid());
		wchar_t *unam = str2wcs( pw->pw_name );
		env_set( L"USER", unam, ENV_GLOBAL );
		free( unam );
	}

	if( env_get_string(L"HOME").missing() )
	{
		const env_var_t unam = env_get_string( L"USER" );
		char *unam_narrow = wcs2str( unam.c_str() );
		struct passwd *pw = getpwnam( unam_narrow );
		wchar_t *dir = str2wcs( pw->pw_dir );
		env_set( L"HOME", dir, ENV_GLOBAL );
		free( dir );		
		free( unam_narrow );
	}	

	env_set_pwd();
	
}
Beispiel #4
0
/**
   Set up default values for various variables if not defined.
 */
static void env_set_defaults()
{

    if (env_get_string(L"USER").missing())
    {
        struct passwd *pw = getpwuid(getuid());
        if (pw->pw_name != NULL)
        {
            const wcstring wide_name = str2wcstring(pw->pw_name);
            env_set(L"USER", wide_name.c_str(), ENV_GLOBAL);
        }
    }

    if (env_get_string(L"HOME").missing())
    {
        const env_var_t unam = env_get_string(L"USER");
        char *unam_narrow = wcs2str(unam.c_str());
        struct passwd *pw = getpwnam(unam_narrow);
        if (pw->pw_dir != NULL)
        {
            const wcstring dir = str2wcstring(pw->pw_dir);
            env_set(L"HOME", dir.c_str(), ENV_GLOBAL);
        }
        free(unam_narrow);
    }

    env_set_pwd();

}
Beispiel #5
0
MODULE initialise_the_program (void)
{
    char
        *db_name,
        *db_user,
        *db_pwd,
        *db_type,
        *db_extra;
    dbyte
        type;

    db_name  = env_get_string ("db_name",   NULL);
    db_user  = env_get_string ("db_user",   NULL);
    db_pwd   = env_get_string ("db_pwd",    NULL);
    db_type  = env_get_string ("db_type",   NULL);
    db_extra = env_get_string ("db_extra",  NULL);
    type = get_db_type (db_type);
    dbio_connect (db_name, db_user, db_pwd, db_extra, TRUE, type);

    buffer.data = mem_alloc (BUFFER_MAX + 1);
    if (buffer.data)
        the_next_event = ok_event;
    else
        the_next_event = error_event;
}
Beispiel #6
0
void kill_add(const wcstring &str)
{
    ASSERT_IS_MAIN_THREAD();
    if (str.empty())
        return;

    wcstring cmd;
    wcstring escaped_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.

       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(), ESCAPE_ALL);
        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;
        }

        const env_var_t disp_wstr = env_get_string(L"DISPLAY");
        if (!disp_wstr.missing())
        {
            escaped_str = escape(str.c_str(), ESCAPE_ALL);
            cmd.assign(L"echo -n ");
            cmd.append(escaped_str);
            cmd.append(L" | xsel -i -b");
        }
    }

    if (! cmd.empty())
    {
        if (exec_subshell(cmd, false /* do not apply exit status */) == -1)
        {
            /*
               Do nothing on failiure
            */
        }

        cut_buffer = escaped_str;
    }
}
Beispiel #7
0
/**
   When fishd isn't started, this function is provided to
   env_universal as a callback, it tries to start up fishd. It's
   implementation is a bit of a hack, since it evaluates a bit of
   shellscript, and it might be used at times when that might not be
   the best idea.
*/
static void start_fishd()
{
    struct passwd *pw = getpwuid(getuid());

    debug(3, L"Spawning new copy of fishd");

    if (!pw)
    {
        debug(0, _(L"Could not get user information"));
        return;
    }

    wcstring cmd = format_string(FISHD_CMD, pw->pw_name);

    /* Prefer the fishd in __fish_bin_dir, if exists */
    const env_var_t bin_dir = env_get_string(L"__fish_bin_dir");
    if (! bin_dir.missing_or_empty())
    {
        wcstring path = bin_dir + L"/fishd";
        if (waccess(path, X_OK) == 0)
        {
            /* The path command just looks like 'fishd', so insert the bin path to make it absolute */
            cmd.insert(0, bin_dir + L"/");
        }
    }
    parser_t &parser = parser_t::principal_parser();
    parser.eval(cmd, io_chain_t(), TOP);
}
Beispiel #8
0
/// Properly sets all locale information.
static void handle_locale(const wchar_t *env_var_name) {
    debug(2, L"handle_locale() called in response to '%ls' changing", env_var_name);
    const char *old_msg_locale = setlocale(LC_MESSAGES, NULL);
    const env_var_t val = env_get_string(env_var_name, ENV_EXPORT);
    const std::string &value = wcs2string(val);
    const std::string &name = wcs2string(env_var_name);
    debug(2, L"locale var %s='%s'", name.c_str(), value.c_str());
    if (val.empty()) {
        unsetenv(name.c_str());
    } else {
        setenv(name.c_str(), value.c_str(), 1);
    }

    char *locale = setlocale(LC_ALL, "");
    fish_setlocale();
    debug(2, L"handle_locale() setlocale(): '%s'", locale);

    const char *new_msg_locale = setlocale(LC_MESSAGES, NULL);
    debug(3, L"old LC_MESSAGES locale: '%s'", old_msg_locale);
    debug(3, L"new LC_MESSAGES locale: '%s'", new_msg_locale);
#ifdef HAVE__NL_MSG_CAT_CNTR
    if (strcmp(old_msg_locale, new_msg_locale)) {
        // Make change known to GNU gettext.
        extern int _nl_msg_cat_cntr;
        _nl_msg_cat_cntr++;
    }
#endif
}
Beispiel #9
0
/* Given a string, return whether it prefixes a path that we could cd into. Return that path in out_path. Expects path to be unescaped. */
static bool is_potential_cd_path(const wcstring &path, const wcstring &working_directory, path_flags_t flags, wcstring *out_path) {
    wcstring_list_t directories;
    
    if (string_prefixes_string(L"./", path)) {
        /* Ignore the CDPATH in this case; just use the working directory */
        directories.push_back(working_directory);
    } else {
        /* Get the CDPATH */
        env_var_t cdpath = env_get_string(L"CDPATH");
        if (cdpath.missing_or_empty())
            cdpath = L".";
        
        /* Tokenize it into directories */
        wcstokenizer tokenizer(cdpath, ARRAY_SEP_STR);
        wcstring next_path;
        while (tokenizer.next(next_path))
        {
            /* Ensure that we use the working directory for relative cdpaths like "." */
            directories.push_back(apply_working_directory(next_path, working_directory));
        }
    }
    
    /* Call is_potential_path with all of these directories */
    bool result = is_potential_path(path, directories, flags | PATH_REQUIRE_DIR, out_path);
#if 0
    if (out_path) {
        printf("%ls -> %ls\n", path.c_str(), out_path->c_str());
    }
#endif
    return result;
}
Beispiel #10
0
/// Print the names of all environment variables in the scope, with or without shortening, with or
/// without values, with or without escaping
static void print_variables(int include_values, int esc, bool shorten_ok, int scope,
                            io_streams_t &streams) {
    wcstring_list_t names = env_get_names(scope);
    sort(names.begin(), names.end());

    for (size_t i = 0; i < names.size(); i++) {
        const wcstring key = names.at(i);
        const wcstring e_key = escape_string(key, 0);

        streams.out.append(e_key);

        if (include_values) {
            env_var_t value = env_get_string(key, scope);
            if (!value.missing()) {
                int shorten = 0;

                if (shorten_ok && value.length() > 64) {
                    shorten = 1;
                    value.resize(60);
                }

                wcstring e_value = esc ? expand_escape_variable(value) : value;

                streams.out.append(L" ");
                streams.out.append(e_value);

                if (shorten) {
                    streams.out.push_back(ellipsis_char);
                }
            }
        }

        streams.out.append(L"\n");
    }
}
Beispiel #11
0
/// Insert a list of all dynamically loaded functions into the specified list.
static void autoload_names(std::set<wcstring> &names, int get_hidden) {
    size_t i;

    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();

    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)) {
            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);
    }
}
Beispiel #12
0
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) {
    std::map<wcstring, env_var_t> result;
    for (wcstring_list_t::const_iterator it = vars.begin(), end = vars.end(); it != end; ++it) {
        result.insert(std::make_pair(*it, env_get_string(*it)));
    }
    return result;
}
Beispiel #13
0
/// Make sure the PATH variable contains something.
static void setup_path() {
    const env_var_t path = env_get_string(L"PATH");
    if (path.missing_or_empty()) {
        const wchar_t *value = L"/usr/bin" ARRAY_SEP_STR L"/bin";
        env_set(L"PATH", value, ENV_GLOBAL | ENV_EXPORT);
    }
}
Beispiel #14
0
rgb_color_t highlight_get_color( int highlight, bool is_background )
{
	size_t i;
	int idx=0;
	rgb_color_t result;

	if( highlight < 0 )
		return rgb_color_t::normal();
	if( highlight > (1<<VAR_COUNT) )
		return rgb_color_t::normal();
	for( i=0; i<VAR_COUNT; i++ )
	{
		if( highlight & (1<<i ))
		{
			idx = i;
			break;
		}
	}
    
	env_var_t val_wstr = env_get_string( highlight_var[idx]); 

//	debug( 1, L"%d -> %d -> %ls", highlight, idx, val );	
	
	if (val_wstr.missing())
		val_wstr = env_get_string( highlight_var[0]);
	
	if( ! val_wstr.missing() )
		result = parse_color( val_wstr, is_background );
	
	if( highlight & HIGHLIGHT_VALID_PATH )
	{
		env_var_t val2_wstr =  env_get_string( L"fish_color_valid_path" );
		const wcstring val2 = val2_wstr.missing() ? L"" : val2_wstr.c_str(); 

		rgb_color_t result2 = parse_color( val2, is_background );
		if( result.is_normal() )
			result = result2;
		else 
		{
			if( result2.is_bold() )
				result.set_bold(true);
			if( result2.is_underline() )
				result.set_underline(true);
		}
	}
	return result;
}
Beispiel #15
0
env_var_t env_vars_snapshot_t::get(const wcstring &key) const {
    // If we represent the current state, bounce to env_get_string.
    if (this->is_current()) {
        return env_get_string(key);
    }
    std::map<wcstring, wcstring>::const_iterator iter = vars.find(key);
    return iter == vars.end() ? env_var_t::missing_var() : env_var_t(iter->second);
}
Beispiel #16
0
wcstring env_get_pwd_slash(void) {
    env_var_t pwd = env_get_string(L"PWD");
    if (pwd.missing_or_empty()) {
        return L"";
    }
    if (!string_suffixes_string(L"/", pwd)) {
        pwd.push_back(L'/');
    }
    return pwd;
}
Beispiel #17
0
env_vars_snapshot_t::env_vars_snapshot_t(const wchar_t *const *keys) {
    ASSERT_IS_MAIN_THREAD();
    wcstring key;
    for (size_t i = 0; keys[i]; i++) {
        key.assign(keys[i]);
        const env_var_t val = env_get_string(key);
        if (!val.missing()) {
            vars[key] = val;
        }
    }
}
Beispiel #18
0
long
env_get_number (
    const char *name,
    long default_value)
{
    char
        *variable_value;

    variable_value = env_get_string (name, NULL);
    return (variable_value? atol (variable_value): default_value);
}
Beispiel #19
0
Bool
env_get_boolean (
    const char *name,
    Bool default_value)
{
    char
        *variable_value;

    variable_value = env_get_string (name, NULL);
    return (variable_value?
           (conv_str_bool (variable_value) != 0): default_value);
}
Beispiel #20
0
/// Properly sets all timezone information.
static void handle_timezone(const wchar_t *env_var_name) {
    debug(2, L"handle_timezone() called in response to '%ls' changing", env_var_name);
    const env_var_t val = env_get_string(env_var_name, ENV_EXPORT);
    const std::string &value = wcs2string(val);
    const std::string &name = wcs2string(env_var_name);
    debug(2, L"timezone var %s='%s'", name.c_str(), value.c_str());
    if (val.empty()) {
        unsetenv(name.c_str());
    } else {
        setenv(name.c_str(), value.c_str(), 1);
    }
    tzset();
}
static wcstring fishd_get_config()
{
    bool done = false;
    wcstring result;

    env_var_t xdg_dir = env_get_string(L"XDG_CONFIG_HOME", ENV_GLOBAL | ENV_EXPORT);
    if (! xdg_dir.missing_or_empty())
    {
        result = xdg_dir;
        append_path_component(result, L"/fish");
        if (!create_directory(result))
        {
            done = true;
        }
    }
    else
    {
        env_var_t home = env_get_string(L"HOME", ENV_GLOBAL | ENV_EXPORT);
        if (! home.missing_or_empty())
        {
            result = home;
            append_path_component(result, L"/.config/fish");
            if (!create_directory(result))
            {
                done = 1;
            }
        }
    }
    
    if (! done)
    {
        /* Bad juju */
        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."));
        result.clear();
    }
    
    return result;
}
Beispiel #22
0
static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring &which_dir,
                        const wcstring &custom_error_msg) {
    bool path_done = false;
    bool using_xdg = false;
    int saved_errno = 0;

    // The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
    // allowing that creates a lock inversion that deadlocks the shell since we're called before
    // uvars are available.
    const env_var_t xdg_dir = env_get_string(xdg_var, ENV_GLOBAL | ENV_EXPORT);
    if (!xdg_dir.missing_or_empty()) {
        using_xdg = true;
        path = xdg_dir + L"/fish";
        if (create_directory(path) != -1) {
            path_done = true;
        } else {
            saved_errno = errno;
        }
    } else {
        const env_var_t home = env_get_string(L"HOME", ENV_GLOBAL | ENV_EXPORT);
        if (!home.missing_or_empty()) {
            path = home + (which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
            if (create_directory(path) != -1) {
                path_done = true;
            } else {
                saved_errno = errno;
            }
        }
    }

    if (!path_done) {
        maybe_issue_path_warning(which_dir, custom_error_msg, using_xdg, xdg_var, path,
                                 saved_errno);
        path.clear();
    }

    return;
}
Beispiel #23
0
int autoload_t::load(const wcstring &cmd, bool reload)
{
    int res;
    CHECK_BLOCK(0);
    ASSERT_IS_MAIN_THREAD();

    env_var_t path_var = env_get_string(env_var_name);

    /*
      Do we know where to look?
    */
    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)
    {
        this->last_path = path_var;
        this->last_path_tokenized.clear();
        tokenize_variable_array(this->last_path, this->last_path_tokenized);
        
        scoped_lock locker(lock);
        this->evict_all_nodes();
    }

    /* Mark that we're loading this. Hang onto the iterator for fast erasing later. Note that std::set has guarantees about not invalidating iterators, so this is safe to do across the callouts below.  */
    typedef std::set<wcstring>::iterator set_iterator_t;
    std::pair<set_iterator_t, bool> insert_result = is_loading_set.insert(cmd);
    set_iterator_t where = insert_result.first;
    bool inserted = insert_result.second;

    /** Warn and fail on infinite recursion. It's OK to do this because this function is only called on the main thread. */
    if (! inserted)
    {
        /* We failed to insert */
        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;
    }
    /* Try loading it */
    res = this->locate_file_and_maybe_load_it(cmd, true, reload, this->last_path_tokenized);

    /* Clean up */
    is_loading_set.erase(where);

    return res;
}
Beispiel #24
0
/**
   Attempts tilde expansion of the string specified, modifying it in place.
*/
static void expand_home_directory(wcstring &input)
{
    const wchar_t * const in = input.c_str();
    if (in[0] == HOME_DIRECTORY)
    {
        int tilde_error = 0;
        size_t tail_idx;
        wcstring home;

        if (in[1] == '/' || in[1] == '\0')
        {
            /* Current users home directory */

            home = env_get_string(L"HOME");
            tail_idx = 1;
        }
        else
        {
            /* Some other users home directory */
            const wchar_t *name_end = wcschr(in, L'/');
            if (name_end)
            {
                tail_idx = name_end - in;
            }
            else
            {
                tail_idx = wcslen(in);
            }
            wcstring name_str = input.substr(1, tail_idx - 1);
            std::string name_cstr = wcs2string(name_str);
            struct passwd *userinfo = getpwnam(name_cstr.c_str());

            if (userinfo == NULL)
            {
                tilde_error = 1;
                input[0] = L'~';
            }
            else
            {
                home = str2wcstring(userinfo->pw_dir);
            }
        }

        if (! tilde_error)
        {
            input.replace(input.begin(), input.begin() + tail_idx, home);
        }
    }
}
Beispiel #25
0
int autoload_t::load(const wcstring &cmd, bool reload)
{
    int res;
    CHECK_BLOCK(0);
    ASSERT_IS_MAIN_THREAD();

    env_var_t path_var = env_get_string(env_var_name);

    /*
      Do we know where to look?
    */
    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)
    {
        this->last_path = path_var;
        scoped_lock locker(lock);
        this->evict_all_nodes();
    }

    /** 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());
        return 1;
    }

    /* Mark that we're loading this */
    is_loading_set.insert(cmd);

    /* Get the list of paths from which we will try to load */
    std::vector<wcstring> 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);

    /* Clean up */
    bool erased = !! is_loading_set.erase(cmd);
    assert(erased);

    return res;
}
Beispiel #26
0
/// Push all curses/terminfo env vars into the global environment where they can be found by those
/// libraries.
static void handle_curses(const wchar_t *env_var_name) {
    debug(2, L"handle_curses() called in response to '%ls' changing", env_var_name);
    const env_var_t val = env_get_string(env_var_name, ENV_EXPORT);
    const std::string &name = wcs2string(env_var_name);
    const std::string &value = wcs2string(val);
    debug(2, L"curses var %s='%s'", name.c_str(), value.c_str());
    if (val.empty()) {
        unsetenv(name.c_str());
    } else {
        setenv(name.c_str(), value.c_str(), 1);
    }
    // TODO: Modify input_init() to allow calling it when the terminfo env vars are dynamically
    // changed. At the present time it can be called just once. Also, we should really only do this
    // if the TERM var is set.
    // input_init();
}
Beispiel #27
0
// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms user variable being
// set.
void update_wait_on_escape_ms() {
    env_var_t escape_time_ms = env_get_string(L"fish_escape_delay_ms");
    if (escape_time_ms.missing_or_empty()) {
        wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
        return;
    }

    long tmp = fish_wcstol(escape_time_ms.c_str());
    if (errno || tmp < 10 || tmp >= 5000) {
        fwprintf(stderr,
                 L"ignoring fish_escape_delay_ms: value '%ls' "
                 L"is not an integer or is < 10 or >= 5000 ms\n",
                 escape_time_ms.c_str());
    } else {
        wait_on_escape_ms = (int)tmp;
    }
}
Beispiel #28
0
/// Does this look like the escape sequence for setting a screen name.
static bool is_screen_name_escape_seq(const wchar_t *code, size_t *resulting_length) {
    bool found = false;
    if (code[1] == L'k') {
        const env_var_t term_name = env_get_string(L"TERM");
        if (!term_name.missing() && string_prefixes_string(L"screen", term_name)) {
            const wchar_t *const screen_name_end_sentinel = L"\x1b\\";
            const wchar_t *screen_name_end = wcsstr(&code[2], screen_name_end_sentinel);
            if (screen_name_end == NULL) {
                // Consider just <esc>k to be the code.
                *resulting_length = 2;
            } else {
                const wchar_t *escape_sequence_end =
                    screen_name_end + wcslen(screen_name_end_sentinel);
                *resulting_length = escape_sequence_end - code;
            }
            found = true;
        }
    }
    return found;
}
Beispiel #29
0
/**
   Check the X clipboard. If it has been changed, add the new
   clipboard contents to the fish killring.
*/
static void kill_check_x_buffer()
{
    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, false /* do not apply exit status */) != -1)
        {

            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 (cut_buffer != new_cut_buffer)
                {
                    cut_buffer = new_cut_buffer;
                    kill_list.push_front(new_cut_buffer);
                }
            }
        }
    }
}
Beispiel #30
0
/**
   The set builtin. Creates, updates and erases environment variables
   and environemnt variable arrays.
*/
static int builtin_set( parser_t &parser, wchar_t **argv ) 
{
	
	/**
	   Variables used for parsing the argument list
	*/
	static const struct woption
		long_options[] = 
		{
			{ 
				L"export", no_argument, 0, 'x' 
			}
			,
			{ 
				L"global", no_argument, 0, 'g' 
			}
			,
			{ 
				L"local", no_argument, 0, 'l'  
			}
			,
			{ 
				L"erase", no_argument, 0, 'e'  
			}
			,
			{ 
				L"names", no_argument, 0, 'n' 
			} 
			,
			{ 
				L"unexport", no_argument, 0, 'u' 
			} 
			,
			{ 
				L"universal", no_argument, 0, 'U'
			}
            ,
			{ 
				L"long", no_argument, 0, 'L'
			} 
			,
			{ 
				L"query", no_argument, 0, 'q' 
			} 
			,
			{ 
				L"help", no_argument, 0, 'h' 
			} 
			,
			{ 
				0, 0, 0, 0 
			}
		}
	;
	
	const wchar_t *short_options = L"+xglenuULqh";

	int argc = builtin_count_args(argv);

	/*
	  Flags to set the work mode
	*/
	int local = 0, global = 0, exportv = 0;
	int erase = 0, list = 0, unexport=0;
	int universal = 0, query=0;
	bool shorten_ok = true;

	/*
	  Variables used for performing the actual work
	*/
	wchar_t *dest = 0;
	int retcode=0;
	int scope;
	int slice=0;
	int i;
	
	wchar_t *bad_char;
	
	
	/* Parse options to obtain the requested operation and the modifiers */
	woptind = 0;
	while (1) 
	{
		int c = wgetopt_long(argc, argv, short_options, long_options, 0);

		if (c == -1) 
		{
			break;
		}
    
		switch(c) 
		{
			case 0:
				break;

			case 'e':
				erase = 1;
				break;

			case 'n':
				list = 1;
				break;

			case 'x':
				exportv = 1;
				break;

			case 'l':
				local = 1;
				break;

			case 'g':
				global = 1;
				break;

			case 'u':
				unexport = 1;
				break;

			case 'U':
				universal = 1;
				break;
            
            case 'L':
                shorten_ok = false;
                break;

			case 'q':
				query = 1;
				break;

			case 'h':
				builtin_print_help( parser, argv[0], stdout_buffer );
				return 0;

			case '?':
				builtin_unknown_option( parser, argv[0], argv[woptind-1] );
				return 1;

			default:
				break;
		}
	}

	/*
	  Ok, all arguments have been parsed, let's validate them
	*/

	/*
	  If we are checking the existance of a variable (-q) we can not
	  also specify scope
	*/

	if( query && (erase || list) )
	{
		append_format(stderr_buffer,
				  BUILTIN_ERR_COMBO,
				  argv[0] );
		
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	

	/* We can't both list and erase varaibles */
	if( erase && list ) 
	{
		append_format(stderr_buffer,
				  BUILTIN_ERR_COMBO,
				  argv[0] );		

		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Variables can only have one scope
	*/
	if( local + global + universal > 1 ) 
	{
		append_format(stderr_buffer,
				   BUILTIN_ERR_GLOCAL,
				   argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Variables can only have one export status
	*/
	if( exportv && unexport ) 
	{
		append_format(stderr_buffer,
				   BUILTIN_ERR_EXPUNEXP,
				   argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}

	/*
	  Calculate the scope value for variable assignement
	*/
	scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (exportv ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER; 

	if( query )
	{
		/*
		  Query mode. Return the number of variables that do not exist
		  out of the specified variables.
		*/
		int i;
		for( i=woptind; i<argc; i++ )
		{
			wchar_t *arg = argv[i];
			int slice=0;

			if( !(dest = wcsdup(arg)))
			{
				DIE_MEM();		
			}

			if( wcschr( dest, L'[' ) )
			{
				slice = 1;
				*wcschr( dest, L'[' )=0;
			}
			
			if( slice )
			{
				std::vector<long> indexes;
				wcstring_list_t result;
				size_t j;
				
                env_var_t dest_str = env_get_string(dest);
                if (! dest_str.missing())
                    tokenize_variable_array( dest_str, result );
								
				if( !parse_index( indexes, arg, dest, result.size() ) )
				{
					builtin_print_help( parser, argv[0], stderr_buffer );
					retcode = 1;
					break;
				}
				for( j=0; j < indexes.size() ; j++ )
				{
					long idx = indexes[j];
					if( idx < 1 || (size_t)idx > result.size() )
					{
						retcode++;
					}
				}
			}
			else
			{
				if( !env_exist( arg, scope ) )
				{
					retcode++;
				}
			}
			
			free( dest );
			
		}
		return retcode;
	}
	
	if( list ) 
	{
		/* Maybe we should issue an error if there are any other arguments? */
		print_variables(0, 0, shorten_ok, scope);
		return 0;
	} 
	
	if( woptind == argc )
	{
		/*
		  Print values of variables
		*/

		if( erase ) 
		{
			append_format(stderr_buffer,
					   _(L"%ls: Erase needs a variable name\n"), 
					   argv[0] );
			
			builtin_print_help( parser, argv[0], stderr_buffer );
			retcode = 1;
		}
		else
		{
			print_variables( 1, 1, shorten_ok, scope );
		}
		
		return retcode;
	}

	if( !(dest = wcsdup(argv[woptind])))
	{
		DIE_MEM();		
	}

	if( wcschr( dest, L'[' ) )
	{
		slice = 1;
		*wcschr( dest, L'[' )=0;
	}
	
	if( !wcslen( dest ) )
	{
		free( dest );
		append_format(stderr_buffer, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	
	if( (bad_char = wcsvarname( dest ) ) )
	{
		append_format(stderr_buffer, BUILTIN_ERR_VARCHAR, argv[0], *bad_char );
		builtin_print_help( parser, argv[0], stderr_buffer );
		free( dest );
		return 1;
	}
	
	if( slice && erase && (scope != ENV_USER) )
	{
		free( dest );
		append_format(stderr_buffer, _(L"%ls: Can not specify scope when erasing array slice\n"), argv[0] );
		builtin_print_help( parser, argv[0], stderr_buffer );
		return 1;
	}
	
	/*
	  set assignment can work in two modes, either using slices or
	  using the whole array. We detect which mode is used here.
	*/
	
	if( slice )
	{

		/*
		  Slice mode
		*/
		int idx_count, val_count;
		wcstring_list_t values;
		std::vector<long> indexes;
		wcstring_list_t result;
		
        const env_var_t dest_str = env_get_string(dest);
        if (! dest_str.missing())
            tokenize_variable_array( dest_str, result );
		
		for( ; woptind<argc; woptind++ )
		{			
			if( !parse_index( indexes, argv[woptind], dest, result.size() ) )
			{
				builtin_print_help( parser, argv[0], stderr_buffer );
				retcode = 1;
				break;
			}
			
			val_count = argc-woptind-1;
			idx_count = indexes.size();

			if( !erase )
			{
				if( val_count < idx_count )
				{
					append_format(stderr_buffer, _(BUILTIN_SET_ARG_COUNT), argv[0] );
					builtin_print_help( parser, argv[0], stderr_buffer );
					retcode=1;
					break;
				}
				if( val_count == idx_count )
				{
					woptind++;
					break;
				}
			}
		}		

		if( !retcode )
		{
			/*
			  Slice indexes have been calculated, do the actual work
			*/

			if( erase )
			{
				erase_values(result, indexes);
				my_env_set( dest, result, scope);
			}
			else
			{
				wcstring_list_t value;
//				al_init(&value);

				while( woptind < argc ) 
				{
					value.push_back( argv[woptind++] );
				}

				if( update_values( result, 
								   indexes,
								   value ) )
				{
					append_format(stderr_buffer, L"%ls: ", argv[0] );
					append_format(stderr_buffer, ARRAY_BOUNDS_ERR );
					stderr_buffer.push_back(L'\n');
				}
				
				my_env_set(dest, result, scope);
								
//				al_destroy( &value );
								
			}			
		}

//		al_foreach( &result, &free );
//		al_destroy( &result );

//		al_destroy(&indexes);
//		al_destroy(&values);
		
	}
	else
	{
		woptind++;
		
		/*
		  No slicing
		*/
		if( erase )
		{
			if( woptind != argc )
			{
				append_format(stderr_buffer, 
						   _(L"%ls: Values cannot be specfied with erase\n"),
						   argv[0] );
				builtin_print_help( parser, argv[0], stderr_buffer );
				retcode=1;
			}
			else
			{
				retcode = env_remove( dest, scope );
			}
		}
		else
		{
            wcstring_list_t val;
			for( i=woptind; i<argc; i++ )
                val.push_back(argv[i]);
			retcode = my_env_set( dest, val, scope );
		}		
	}
	
	free( dest );
	
	return retcode;

}