Example #1
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();

}
Example #2
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();
	
}
Example #3
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);
    }
}
Example #4
0
void env_init(const struct config_paths_t *paths /* or NULL */)
{
    /*
      env_read_only variables can not be altered directly by the user
    */

    const wchar_t * const ro_keys[] =
    {
        L"status",
        L"history",
        L"version",
        L"_",
        L"LINES",
        L"COLUMNS",
        L"PWD",
        //L"SHLVL", // will be inserted a bit lower down
        L"FISH_VERSION",
    };
    for (size_t i=0; i < sizeof ro_keys / sizeof *ro_keys; i++)
    {
        env_read_only.insert(ro_keys[i]);
    }

    /*
       Names of all dynamically calculated variables
       */
    env_electric.insert(L"history");
    env_electric.insert(L"status");
    env_electric.insert(L"umask");
    env_electric.insert(L"COLUMNS");
    env_electric.insert(L"LINES");

    top = new env_node_t;
    global_env = top;
    global = &top->env;

    /*
      Now the environemnt variable handling is set up, the next step
      is to insert valid data
    */

    /*
      Import environment variables
    */
    for (char **p = (environ ? environ : __environ); p && *p; p++)
    {
        const wcstring key_and_val = str2wcstring(*p); //like foo=bar
        size_t eql = key_and_val.find(L'=');
        if (eql == wcstring::npos)
        {
            // no equals found
            if (is_read_only(key_and_val) || is_electric(key_and_val)) continue;
            env_set(key_and_val, L"", ENV_EXPORT | ENV_GLOBAL);
        }
        else
        {
            wcstring key = key_and_val.substr(0, eql);
            if (is_read_only(key) || is_electric(key)) continue;
            wcstring val = key_and_val.substr(eql + 1);
            if (variable_is_colon_delimited_array(key))
            {
                std::replace(val.begin(), val.end(), L':', ARRAY_SEP);
            }

            env_set(key, val.c_str(), ENV_EXPORT | ENV_GLOBAL);
        }
    }

    /* Set the given paths in the environment, if we have any */
    if (paths != NULL)
    {
        env_set(FISH_DATADIR_VAR, paths->data.c_str(), ENV_GLOBAL);
        env_set(FISH_SYSCONFDIR_VAR, paths->sysconf.c_str(), ENV_GLOBAL);
        env_set(FISH_HELPDIR_VAR, paths->doc.c_str(), ENV_GLOBAL);
        env_set(FISH_BIN_DIR, paths->bin.c_str(), ENV_GLOBAL);
    }

    /*
      Set up the PATH variable
    */
    setup_path();

    /*
      Set up the USER variable
    */
    if (env_get_string(L"USER").missing_or_empty())
    {
        const struct passwd *pw = getpwuid(getuid());
        if (pw && pw->pw_name)
        {
            const wcstring uname = str2wcstring(pw->pw_name);
            env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
        }
    }

    /*
      Set up the version variables
    */
    wcstring version = str2wcstring(get_fish_version());
    env_set(L"version", version.c_str(), ENV_GLOBAL);
    env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);

    /*
      Set up SHLVL variable
    */
    const env_var_t shlvl_str = env_get_string(L"SHLVL");
    wcstring nshlvl_str = L"1";
    if (! shlvl_str.missing())
    {
        wchar_t *end;
        long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
        while (iswspace(*end)) ++end; /* skip trailing whitespace */
        if (shlvl_i >= 0 && *end == '\0')
        {
            nshlvl_str = to_string<long>(shlvl_i + 1);
        }
    }
    env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT);
    env_read_only.insert(L"SHLVL");

    /* Set up the HOME variable */
    if (env_get_string(L"HOME").missing_or_empty())
    {
        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 | ENV_EXPORT);
        }
        free(unam_narrow);
    }

    /* Set PWD */
    env_set_pwd();

    /* Set up universal variables. The empty string means to use the deafult path. */
    assert(s_universal_variables == NULL);
    s_universal_variables = new env_universal_t(L"");
    s_universal_variables->load();

    /* Set g_log_forks */
    env_var_t log_forks = env_get_string(L"fish_log_forks");
    g_log_forks = ! log_forks.missing_or_empty() && from_string<bool>(log_forks);

    /* Set g_use_posix_spawn. Default to true. */
    env_var_t use_posix_spawn = env_get_string(L"fish_use_posix_spawn");
    g_use_posix_spawn = (use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn));

    /* Set fish_bind_mode to "default" */
    env_set(FISH_BIND_MODE_VAR, DEFAULT_BIND_MODE, ENV_GLOBAL);

    /*
      Now that the global scope is fully initialized, add a toplevel local
      scope. This same local scope will persist throughout the lifetime of the
      fish process, and it will ensure that `set -l` commands run at the
      command-line don't affect the global scope.
    */
    env_push(false);
}
Example #5
0
/**
  Properly sets all locale information
*/
static void handle_locale()
{
    const env_var_t lc_all = env_get_string(L"LC_ALL");
    const wcstring old_locale = wsetlocale(LC_MESSAGES, NULL);

    /*
      Array of locale constants corresponding to the local variable names defined in locale_variable
    */
    static const int cat[] =
    {
        0,
        LC_ALL,
        LC_COLLATE,
        LC_CTYPE,
        LC_MESSAGES,
        LC_MONETARY,
        LC_NUMERIC,
        LC_TIME
    }
    ;

    if (!lc_all.missing())
    {
        wsetlocale(LC_ALL, lc_all.c_str());
    }
    else
    {
        const env_var_t lang = env_get_string(L"LANG");
        if (!lang.missing())
        {
            wsetlocale(LC_ALL, lang.c_str());
        }

        for (int i=2; locale_variable[i]; i++)
        {
            const env_var_t val = env_get_string(locale_variable[i]);

            if (!val.missing())
            {
                wsetlocale(cat[i], val.c_str());
            }
        }
    }

    const wcstring new_locale = wsetlocale(LC_MESSAGES, NULL);
    if (old_locale != new_locale)
    {

        /*
           Try to make change known to gettext. Both changing
           _nl_msg_cat_cntr and calling dcgettext might potentially
           tell some gettext implementation that the translation
           strings should be reloaded. We do both and hope for the
           best.
        */

        extern int _nl_msg_cat_cntr;
        _nl_msg_cat_cntr++;

        fish_dcgettext("fish", "Changing language to English", LC_MESSAGES);

        if (get_is_interactive())
        {
            debug(2, _(L"Changing language to English"));
        }
    }
}
Example #6
0
void env_init(const struct config_paths_t *paths /* or NULL */)
{
    /*
      env_read_only variables can not be altered directly by the user
    */

    const wchar_t * const ro_keys[] =
    {
        L"status",
        L"history",
        L"version",
        L"_",
        L"LINES",
        L"COLUMNS",
        L"PWD",
        L"SHLVL",
        L"FISH_VERSION",
    };
    for (size_t i=0; i < sizeof ro_keys / sizeof *ro_keys; i++)
    {
        env_read_only.insert(ro_keys[i]);
    }

    /*
      HOME and USER should be writeable by root, since this can be a
      convenient way to install software.
    */
    if (getuid() != 0)
    {
        env_read_only.insert(L"HOME");
        env_read_only.insert(L"USER");
    }

    /*
       Names of all dynamically calculated variables
       */
    env_electric.insert(L"history");
    env_electric.insert(L"status");
    env_electric.insert(L"umask");

    top = new env_node_t;
    global_env = top;
    global = &top->env;

    /*
      Now the environemnt variable handling is set up, the next step
      is to insert valid data
    */

    /*
      Import environment variables
    */
    for (char **p = (environ ? environ : __environ); p && *p; p++)
    {
        const wcstring key_and_val = str2wcstring(*p); //like foo=bar
        size_t eql = key_and_val.find(L'=');
        if (eql == wcstring::npos)
        {
            // no equals found
            env_set(key_and_val, L"", ENV_EXPORT);
        }
        else
        {
            wcstring key = key_and_val.substr(0, eql);
            wcstring val = key_and_val.substr(eql + 1);
            if (variable_can_be_array(val))
            {
                std::replace(val.begin(), val.end(), L':', ARRAY_SEP);
            }

            env_set(key, val.c_str(), ENV_EXPORT | ENV_GLOBAL);
        }
    }

    /* Set the given paths in the environment, if we have any */
    if (paths != NULL)
    {
        env_set(FISH_DATADIR_VAR, paths->data.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_SYSCONFDIR_VAR, paths->sysconf.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_HELPDIR_VAR, paths->doc.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_BIN_DIR, paths->bin.c_str(), ENV_GLOBAL | ENV_EXPORT);
    }

    /*
      Set up the PATH variable
    */
    setup_path();

    /*
      Set up the USER variable
    */
    const struct passwd *pw = getpwuid(getuid());
    if (pw && pw->pw_name)
    {
        const wcstring uname = str2wcstring(pw->pw_name);
        env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
    }

    /*
      Set up the version variables
    */
    wcstring version = str2wcstring(FISH_BUILD_VERSION);
    env_set(L"version", version.c_str(), ENV_GLOBAL);
    env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);

    const env_var_t fishd_dir_wstr = env_get_string(L"FISHD_SOCKET_DIR");
    const env_var_t user_dir_wstr = env_get_string(L"USER");

    wchar_t * fishd_dir = fishd_dir_wstr.missing()?NULL:const_cast<wchar_t*>(fishd_dir_wstr.c_str());
    wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());

    env_universal_init(fishd_dir , user_dir ,
                       &start_fishd,
                       &universal_callback);

    /*
      Set up SHLVL variable
    */
    const env_var_t shlvl_str = env_get_string(L"SHLVL");
    wcstring nshlvl_str = L"1";
    if (! shlvl_str.missing())
    {
        long shlvl_i = wcstol(shlvl_str.c_str(), NULL, 10);
        if (shlvl_i >= 0)
        {
            nshlvl_str = to_string<long>(shlvl_i + 1);
        }
    }
    env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT);

    /* Set correct defaults for e.g. USER and HOME variables */
    env_set_defaults();

    /* Set g_log_forks */
    env_var_t log_forks = env_get_string(L"fish_log_forks");
    g_log_forks = ! log_forks.missing_or_empty() && from_string<bool>(log_forks);

    /* Set g_use_posix_spawn. Default to true. */
    env_var_t use_posix_spawn = env_get_string(L"fish_use_posix_spawn");
    g_use_posix_spawn = (use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn));
}
Example #7
0
void env_init(const struct config_paths_t *paths /* or NULL */)
{
	char **p;
	struct passwd *pw;
	wchar_t *uname;
	wchar_t *version;
	
	/*
	  env_read_only variables can not be altered directly by the user
	*/
    
    const wchar_t * const ro_keys[] = {
        L"status",
        L"history",
        L"version",
        L"_",
        L"LINES",
        L"COLUMNS",
        L"PWD",
        L"SHLVL",
    };
    for (size_t i=0; i < sizeof ro_keys / sizeof *ro_keys; i++) {
        env_read_only.insert(ro_keys[i]);
    }
	
	/*
	  HOME and USER should be writeable by root, since this can be a
	  convenient way to install software.
	*/
	if( getuid() != 0 )
	{
        env_read_only.insert(L"HOME");
        env_read_only.insert(L"USER");
	}
	
	/*
     Names of all dynamically calculated variables
     */
    env_electric.insert(L"history");
    env_electric.insert(L"status");
    env_electric.insert(L"umask");
    
	top = new env_node_t;
	global_env = top;
	global = &top->env;	
	
	/*
	  Now the environemnt variable handling is set up, the next step
	  is to insert valid data
	*/
	    
	/*
	  Import environment variables
	*/
	for( p=environ?environ:__environ; p && *p; p++ )
	{
		wchar_t *key, *val;
		
		key = str2wcs(*p);

		if( !key )
		{
			continue;
		}
		
		val = wcschr( key, L'=' );

		if( val == 0 )
		{
			env_set( key, L"", ENV_EXPORT );
		}
		else
		{ 
			*val = L'\0';
			val++;
            
            //fwprintf( stderr, L"Set $%ls to %ls\n", key, val );
            if (variable_can_be_array(val)) {
                for (size_t i=0; val[i] != L'\0'; i++) {
                    if( val[i] == L':' ) {
                        val[i] = ARRAY_SEP;
                    }
                }
            }

			env_set( key, val, ENV_EXPORT | ENV_GLOBAL );
		}		
		free(key);
	}
	
    /* Set the given paths in the environment, if we have any */
    if (paths != NULL)
    {
        env_set(FISH_DATADIR_VAR, paths->data.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_SYSCONFDIR_VAR, paths->sysconf.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_HELPDIR_VAR, paths->doc.c_str(), ENV_GLOBAL | ENV_EXPORT);
        env_set(FISH_BIN_DIR, paths->bin.c_str(), ENV_GLOBAL | ENV_EXPORT);
    }
    
	/*
	  Set up the PATH variable
	*/
	setup_path();

	/*
	  Set up the USER variable
	*/
	pw = getpwuid( getuid() );
	if( pw )
	{
		uname = str2wcs( pw->pw_name );
		env_set( L"USER", uname, ENV_GLOBAL | ENV_EXPORT );
		free( uname );
	}

	/*
	  Set up the version variable
	*/
	version = str2wcs( PACKAGE_VERSION );
	env_set( L"version", version, ENV_GLOBAL );
	free( version );

	const env_var_t fishd_dir_wstr = env_get_string( L"FISHD_SOCKET_DIR");
	const env_var_t user_dir_wstr = env_get_string( L"USER" );

	wchar_t * fishd_dir = fishd_dir_wstr.missing()?NULL:const_cast<wchar_t*>(fishd_dir_wstr.c_str());
	wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());

	env_universal_init(fishd_dir , user_dir , 
						&start_fishd,
						&universal_callback );

	/*
	  Set up SHLVL variable
	*/
	const env_var_t shlvl_str = env_get_string( L"SHLVL" );
    wcstring nshlvl_str = L"1";
	if (! shlvl_str.missing())
	{
        long shlvl_i = wcstol(shlvl_str.c_str(), NULL, 10);
        if (shlvl_i >= 0)
        {
            nshlvl_str = format_string(L"%ld", 1 + shlvl_i);
        }
	}
    env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT );

	/* Set correct defaults for e.g. USER and HOME variables */
	env_set_defaults();
    
    /* Set g_log_forks */
    env_var_t log_forks = env_get_string(L"fish_log_forks");
    g_log_forks = ! log_forks.missing_or_empty() && from_string<bool>(log_forks);
    
    /* Set g_use_posix_spawn. Default to true. */
    env_var_t use_posix_spawn = env_get_string(L"fish_use_posix_spawn");
    g_use_posix_spawn = (use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn));
}
Example #8
0
/**
   Calculate the width of the specified prompt. Does some clever magic
   to detect common escape sequences that may be embeded in a prompt,
   such as color codes.
*/
static size_t calc_prompt_width( const wchar_t *prompt )
{
	size_t res = 0;
	size_t j, k;

	for( j=0; prompt[j]; j++ )
	{
		if( prompt[j] == L'\x1b' )
		{
			/*
			  This is the start of an escape code. Try to guess it's width.
			*/
			size_t p;
			int len=0;
			bool found = false;
			
			/*
			  Detect these terminfo color escapes with parameter
			  value 0..7, all of which don't move the cursor
			*/
			char * const esc[] =
				{
					set_a_foreground,
					set_a_background,
					set_foreground,
					set_background,
				}
			;

			/*
			  Detect these semi-common terminfo escapes without any
			  parameter values, all of which don't move the cursor
			*/
			char * const esc2[] =
				{
					enter_bold_mode,
					exit_attribute_mode,
					enter_underline_mode,
					exit_underline_mode,
					enter_standout_mode,
					exit_standout_mode,
					flash_screen,
					enter_subscript_mode,
					exit_subscript_mode,
					enter_superscript_mode,
					exit_superscript_mode,
					enter_blink_mode,
					enter_italics_mode,
					exit_italics_mode,
					enter_reverse_mode,
					enter_shadow_mode,
					exit_shadow_mode,
					enter_standout_mode,
					exit_standout_mode,
					enter_secure_mode
				}
			;

			for( p=0; p < sizeof esc / sizeof *esc && !found; p++ )
			{
				if( !esc[p] )
					continue;

				for( k=0; k<8; k++ )
				{
					len = try_sequence( tparm(esc[p],k), &prompt[j] );
					if( len )
					{
						j += (len-1);
						found = true;
						break;
					}
				}
			}
            
            // PCA for term256 support, let's just detect the escape codes directly
            if (! found) {
                len = is_term256_escape(&prompt[j]);
                if (len) {
                    j += (len - 1);
                    found = true;
                }
            }


			for( p=0; p < (sizeof(esc2)/sizeof(char *)) && !found; p++ )
			{
				if( !esc2[p] )
					continue;
				/*
				  Test both padded and unpadded version, just to
				  be safe. Most versions of tparm don't actually
				  seem to do anything these days.
				*/
				len = maxi( try_sequence( tparm(esc2[p]), &prompt[j] ),
					    try_sequence( esc2[p], &prompt[j] ));
					
				if( len )
				{
					j += (len-1);
					found = true;
				}
			}
				
			if( !found )
			{
				if( prompt[j+1] == L'k' )
				{
					const env_var_t term_name = env_get_string( L"TERM" );
					if( !term_name.missing() && wcsstr( term_name.c_str(), L"screen" ) == term_name )
					{
						const wchar_t *end;
						j+=2;
						found = true;
						end = wcsstr( &prompt[j], L"\x1b\\" );
						if( end )
						{
							/*
							  You'd thing this should be
							  '(end-prompt)+2', in order to move j
							  past the end of the string, but there is
							  a 'j++' at the end of each lap, so j
							  should always point to the last menged
							  character, e.g. +1.
							*/
							j = (end-prompt)+1;
						}
						else
						{
							break;
						}
					}						
				}					
			}
				
		}
		else if( prompt[j] == L'\t' )
		{
			res = next_tab_stop( res );
		}
		else if( prompt[j] == L'\n' )
		{
			res = 0;
		}
		else
		{
			/*
			  Ordinary decent character. Just add width.
			*/
			res += fish_wcwidth( prompt[j] );
		}
	}
	return res;
}
Example #9
0
bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env_var_t &cdpath)
{
    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 (S_ISDIR(buf.st_mode))
            {
                result = dir_str;
                success = true;
            }
            else
            {
                err = ENOTDIR;
            }

        }
    }
    else
    {

        wcstring path = L".";

        // Respect CDPATH
        env_var_t cdpath = env_get_string(L"CDPATH");
        if (! cdpath.missing_or_empty())
        {
            path = cdpath.c_str();
        }

        wcstokenizer tokenizer(path, ARRAY_SEP_STR);
        wcstring next_path;
        while (tokenizer.next(next_path))
        {
            expand_tilde(next_path);
            if (next_path.size() == 0) continue;

            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))
                {
                    result = whole_path;
                    success = true;
                    break;
                }
                else
                {
                    err = ENOTDIR;
                }
            }
            else
            {
                if (lwstat(whole_path, &buf) == 0)
                {
                    err = EROTTEN;
                }
            }
        }
    }


    if (!success)
    {
        errno = err;
    }

    return res;
}