/**
   Silly function
*/
static void  builtin_complete_remove2(const wchar_t *cmd,
                                      int cmd_type,
                                      const wchar_t *short_opt,
                                      const wcstring_list_t &gnu_opt,
                                      const wcstring_list_t &old_opt)
{
    const wchar_t *s = (wchar_t *)short_opt;
    if (*s)
    {
        for (; *s; s++)
        {
            if (old_opt.empty() && gnu_opt.empty())
            {
                complete_remove(cmd,
                                cmd_type,
                                *s,
                                0,
                                0);

            }
            else
            {
                builtin_complete_remove3(cmd,
                                         cmd_type,
                                         *s,
                                         gnu_opt,
                                         0);
                builtin_complete_remove3(cmd,
                                         cmd_type,
                                         *s,
                                         old_opt,
                                         1);
            }
        }
    }
    else if (gnu_opt.empty() && old_opt.empty())
    {
        complete_remove(cmd,
                        cmd_type,
                        0,
                        0,
                        0);
    }
    else
    {
        builtin_complete_remove3(cmd,
                                 cmd_type,
                                 0,
                                 gnu_opt,
                                 0);
        builtin_complete_remove3(cmd,
                                 cmd_type,
                                 0,
                                 old_opt,
                                 1);

    }


}
/**
   Silly function
*/
static void  builtin_complete_remove(const wcstring_list_t &cmd,
                                     const wcstring_list_t &path,
                                     const wchar_t *short_opt,
                                     const wcstring_list_t &gnu_opt,
                                     const wcstring_list_t &old_opt)
{
    for (size_t i=0; i<cmd.size(); i++)
    {
        builtin_complete_remove2(cmd.at(i).c_str(),
                                 COMMAND,
                                 short_opt,
                                 gnu_opt,
                                 old_opt);
    }

    for (size_t i=0; i<path.size(); i++)
    {
        builtin_complete_remove2(path.at(i).c_str(),
                                 PATH,
                                 short_opt,
                                 gnu_opt,
                                 old_opt);
    }

}
Exemple #3
0
static void update_export_array_if_necessary(bool recalc) {
    ASSERT_IS_MAIN_THREAD();
    if (recalc && !get_proc_had_barrier()) {
        set_proc_had_barrier(true);
        env_universal_barrier();
    }

    if (has_changed_exported) {
        std::map<wcstring, wcstring> vals;

        debug(4, L"env_export_arr() recalc");

        get_exported(top, &vals);

        if (uvars()) {
            const wcstring_list_t uni = uvars()->get_names(true, false);
            for (size_t i = 0; i < uni.size(); i++) {
                const wcstring &key = uni.at(i);
                const env_var_t val = uvars()->get(key);

                if (!val.missing() && val != ENV_NULL) {
                    // Note that std::map::insert does NOT overwrite a value already in the map,
                    // which we depend on here.
                    vals.insert(std::pair<wcstring, wcstring>(key, val));
                }
            }
        }

        std::vector<std::string> local_export_buffer;
        export_func(vals, local_export_buffer);
        export_array.set(local_export_buffer);
        has_changed_exported = false;
    }
}
Exemple #4
0
/// This handles the common case of setting the entire var to a set of values.
static int set_var_array(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t *varname,
                         wcstring_list_t &new_values, int argc, wchar_t **argv, parser_t &parser,
                         io_streams_t &streams) {
    UNUSED(cmd);
    UNUSED(parser);
    UNUSED(streams);

    if (opts.prepend || opts.append) {
        if (opts.prepend) {
            for (int i = 0; i < argc; i++) new_values.push_back(argv[i]);
        }
        auto var_str = parser.vars().get(varname, ENV_DEFAULT);
        wcstring_list_t var_array;
        if (var_str) var_str->to_list(var_array);
        new_values.insert(new_values.end(), var_array.begin(), var_array.end());

        if (opts.append) {
            for (int i = 0; i < argc; i++) new_values.push_back(argv[i]);
        }
    } else {
        for (int i = 0; i < argc; i++) new_values.push_back(argv[i]);
    }

    return STATUS_CMD_OK;
}
static void builtin_complete_remove_cmd(const wcstring &cmd,
                                        int cmd_type,
                                        const wchar_t *short_opt,
                                        const wcstring_list_t &gnu_opt,
                                        const wcstring_list_t &old_opt)
{
    bool removed = false;
    size_t i;
    for (i=0; short_opt[i] != L'\0'; i++)
    {
        complete_remove(cmd, cmd_type, wcstring(1, short_opt[i]), option_type_short);
        removed = true;
    }
    
    for (i=0; i < old_opt.size(); i++)
    {
        complete_remove(cmd, cmd_type, old_opt.at(i), option_type_single_long);
        removed = true;
    }
    
    for (i=0; i < gnu_opt.size(); i++)
    {
        complete_remove(cmd, cmd_type, gnu_opt.at(i), option_type_double_long);
        removed = true;
    }
    
    if (! removed)
    {
        // This means that all loops were empty
        complete_remove_all(cmd, cmd_type);
    }
}
Exemple #6
0
wcstring_list_t env_get_names(int flags)
{
    scoped_lock lock(env_lock);

    wcstring_list_t result;
    std::set<wcstring> names;
    int show_local = flags & ENV_LOCAL;
    int show_global = flags & ENV_GLOBAL;
    int show_universal = flags & ENV_UNIVERSAL;

    env_node_t *n=top;
    const bool show_exported = (flags & ENV_EXPORT) || !(flags & ENV_UNEXPORT);
    const bool show_unexported = (flags & ENV_UNEXPORT) || !(flags & ENV_EXPORT);

    if (!show_local && !show_global && !show_universal)
    {
        show_local =show_universal = show_global=1;
    }

    if (show_local)
    {
        while (n)
        {
            if (n == global_env)
                break;

            add_key_to_string_set(n->env, &names, show_exported, show_unexported);
            if (n->new_scope)
                break;
            else
                n = n->next;

        }
    }

    if (show_global)
    {
        add_key_to_string_set(global_env->env, &names, show_exported, show_unexported);
        if (show_unexported)
        {
            result.insert(result.end(), env_electric.begin(), env_electric.end());
        }

        if (show_exported)
        {
            result.push_back(L"COLUMNS");
            result.push_back(L"LINES");
        }

    }

    if (show_universal && uvars())
    {
        const wcstring_list_t uni_list = uvars()->get_names(show_exported, show_unexported);
        names.insert(uni_list.begin(), uni_list.end());
    }

    result.insert(result.end(), names.begin(), names.end());
    return result;
}
Exemple #7
0
void function_prepare_environment(const wcstring &name, const wchar_t *const *argv,
                                  const std::map<wcstring, env_var_t> &inherited_vars) {
    // Three components of the environment:
    // 1. argv
    // 2. named arguments
    // 3. inherited variables
    env_set_argv(argv);

    const wcstring_list_t named_arguments = function_get_named_arguments(name);
    if (!named_arguments.empty()) {
        const wchar_t *const *arg;
        size_t i;
        for (i = 0, arg = argv; i < named_arguments.size(); i++) {
            env_set(named_arguments.at(i).c_str(), *arg, ENV_LOCAL | ENV_USER);

            if (*arg) arg++;
        }
    }

    for (std::map<wcstring, env_var_t>::const_iterator it = inherited_vars.begin(),
                                                       end = inherited_vars.end();
         it != end; ++it) {
        env_set(it->first, it->second.missing() ? NULL : it->second.c_str(), ENV_LOCAL | ENV_USER);
    }
}
Exemple #8
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;
}
Exemple #9
0
static int update_values( wcstring_list_t &list, 
						  std::vector<long> &indexes,
						  wcstring_list_t &values ) 
{
	size_t i;

	/* Replace values where needed */
	for( i = 0; i < indexes.size(); i++ ) 
	{
		/*
		  The '- 1' below is because the indices in fish are
		  one-based, but the vector uses zero-based indices
		*/
		long ind = indexes[i] - 1;
		const wcstring newv = values[ i ];
		if( ind < 0 )
		{
			return 1;
		}
        if ( ind >= list.size() )
        {
            list.resize( ind+1 );
        }
		
//		free((void *) al_get(list, ind));
		list[ ind ] = newv; 
	}
  
	return 0;
}
static void print_colors(io_streams_t &streams) {
    const wcstring_list_t result = rgb_color_t::named_color_names();
    size_t i;
    for (i = 0; i < result.size(); i++) {
        streams.out.append(result.at(i));
        streams.out.push_back(L'\n');
    }
}
/// Print terminfo key binding names to string buffer used for standard output.
///
/// \param all if set, all terminfo key binding names will be printed. If not set, only ones that
/// are defined for this terminal are printed.
void builtin_bind_t::key_names(bool all, io_streams_t &streams) {
    const wcstring_list_t names = input_terminfo_get_names(!all);
    for (size_t i = 0; i < names.size(); i++) {
        const wcstring &name = names.at(i);

        streams.out.append_format(L"%ls\n", name.c_str());
    }
}
static void print_colors(void)
{
    const wcstring_list_t result = rgb_color_t::named_color_names();
    size_t i;
    for (i=0; i < result.size(); i++)
    {
        stdout_buffer.append(result.at(i));
        stdout_buffer.push_back(L'\n');
    }
}
Exemple #13
0
static bool run_test_test(int expected, wcstring_list_t &lst) {
    parser_t parser(PARSER_TYPE_GENERAL, true);
    size_t i, count = lst.size();
    wchar_t **argv = new wchar_t *[count+2];
    argv[0] = (wchar_t *)L"test";
    for (i=0; i < count; i++) {
        argv[i+1] = (wchar_t *)lst.at(i).c_str();
    }
    argv[i+1] = NULL;
    int result = builtin_test(parser, argv);
    delete[] argv;
    return expected == result;
}
/**
   Silly function
*/
static void builtin_complete_remove3(const wchar_t *cmd,
                                     int cmd_type,
                                     wchar_t short_opt,
                                     const wcstring_list_t &long_opt)
{
    for (size_t i=0; i<long_opt.size(); i++)
    {
        complete_remove(cmd,
                        cmd_type,
                        short_opt,
                        long_opt.at(i).c_str());
    }
}
Exemple #15
0
void history_tests_t::test_history_races_pound_on_history()
{
    /* Called in child process to modify history */
    history_t *hist = new history_t(L"race_test");
    hist->chaos_mode = true;
    const wcstring_list_t lines = generate_history_lines(getpid());
    for (size_t idx = 0; idx < lines.size(); idx++)
    {
        const wcstring &line = lines.at(idx);
        hist->add(line);
        hist->save();
    }
    delete hist;
}
/// Silly function.
static void builtin_complete_add(const wcstring_list_t &cmd, const wcstring_list_t &path,
                                 const wchar_t *short_opt, wcstring_list_t &gnu_opt,
                                 wcstring_list_t &old_opt, int result_mode,
                                 const wchar_t *condition, const wchar_t *comp, const wchar_t *desc,
                                 int flags) {
    for (size_t i = 0; i < cmd.size(); i++) {
        builtin_complete_add2(cmd.at(i).c_str(), COMMAND, short_opt, gnu_opt, old_opt, result_mode,
                              condition, comp, desc, flags);
    }

    for (size_t i = 0; i < path.size(); i++) {
        builtin_complete_add2(path.at(i).c_str(), PATH, short_opt, gnu_opt, old_opt, result_mode,
                              condition, comp, desc, flags);
    }
}
Exemple #17
0
/**
   Erase from a list of wcstring values at specified indexes 
*/
static void erase_values(wcstring_list_t &list, const std::vector<long> &indexes) 
{
    // Make a set of indexes.
    // This both sorts them into ascending order and removes duplicates.
    const std::set<long> indexes_set(indexes.begin(), indexes.end());
    
    // Now walk the set backwards, so we encounter larger indexes first, and remove elements at the given (1-based) indexes.
    std::set<long>::const_reverse_iterator iter;
    for (iter = indexes_set.rbegin(); iter != indexes_set.rend(); iter++) {
        long val = *iter;
        if (val > 0 && val <= list.size()) {
            // One-based indexing!
            list.erase(list.begin() + val - 1);
        }
    }
}
static bool binary_primary_evaluate(test_expressions::token_t token, const wcstring &left, const wcstring &right, wcstring_list_t &errors)
{
    using namespace test_expressions;
    long long left_num, right_num;
    switch (token)
    {
        case test_string_equal:
            return left == right;

        case test_string_not_equal:
            return left != right;

        case test_number_equal:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num == right_num;

        case test_number_not_equal:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num != right_num;

        case test_number_greater:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num > right_num;

        case test_number_greater_equal:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num >= right_num;

        case test_number_lesser:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num < right_num;

        case test_number_lesser_equal:
            return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num <= right_num;

        default:
            errors.push_back(format_string(L"Unknown token type in %s", __func__));
            return false;
    }
}
Exemple #19
0
// IEEE 1003.1 says nothing about what it means for two strings to be "algebraically equal". For
// example, should we interpret 0x10 as 0, 10, or 16? Here we use only base 10 and use wcstoll,
// which allows for leading + and -, and whitespace. This is consistent, albeit a bit more lenient
// since we allow trailing whitespace, with other implementations such as bash.
static bool parse_number(const wcstring &arg, long long *out, wcstring_list_t &errors) {
    *out = fish_wcstoll(arg.c_str());
    if (errno) {
        errors.push_back(format_string(_(L"invalid integer '%ls'"), arg.c_str()));
    }
    return !errno;
}
Exemple #20
0
/**
   Replace completion strings with a comp_t structure
*/
static std::vector<comp_t *> mangle_completions( wcstring_list_t &lst, const wchar_t *prefix )
{
    std::vector<comp_t *> result;
	for( size_t i=0; i<lst.size(); i++ )
	{
        wcstring &next = lst.at(i);
		size_t start, end;
        
        comp_t zerod = {};
		comp_t *comp = new comp_t(zerod);
		
		for( start=end=0; 1; end++ )
		{
			wchar_t c = next.c_str()[end];
			
			if( (c == COMPLETE_ITEM_SEP) || (c==COMPLETE_SEP) || !c)
			{
                wcstring start2 = wcstring(next, start, end - start);
                wcstring str = escape_string(start2, ESCAPE_ALL | ESCAPE_NO_QUOTED);
				comp->comp_width += my_wcswidth( str.c_str() );
				comp->comp.push_back(str);
				start = end+1;
			}

			if( c == COMPLETE_SEP )
			{
				comp->desc = next.c_str() + start;
				break;
			}	
			
			if( !c )
				break;
			
		}

		comp->comp_width  += (int)(my_wcswidth(prefix)*comp->comp.size() + 2*(comp->comp.size()-1));
		comp->desc_width = comp->desc.empty()?0:my_wcswidth( comp->desc.c_str() );
		
		comp->pref_width = comp->comp_width + comp->desc_width + (comp->desc_width?4:0);
		
        result.push_back(comp);
	}
	
	recalc_width( result, prefix );
    return result;
}
Exemple #21
0
bool unary_operator::evaluate(wcstring_list_t &errors) {
    if (token == test_bang) {
        assert(subject.get());
        return !subject->evaluate(errors);
    }

    errors.push_back(format_string(L"Unknown token type in %s", __func__));
    return false;
}
Exemple #22
0
// Validate the given path `list`. If there are any entries referring to invalid directories which
// contain a colon, then complain. Return true if any path element was valid, false if not.
static bool validate_path_warning_on_colons(const wchar_t *cmd,
                                            const wchar_t *key,  //!OCLINT(npath complexity)
                                            const wcstring_list_t &list, io_streams_t &streams,
                                            const environment_t &vars) {
    // Always allow setting an empty value.
    if (list.empty()) return true;

    bool any_success = false;

    // Don't bother validating (or complaining about) values that are already present. When
    // determining already-present values, use ENV_DEFAULT instead of the passed-in scope because
    // in:
    //
    //   set -l PATH stuff $PATH
    //
    // where we are temporarily shadowing a variable, we want to compare against the shadowed value,
    // not the (missing) local value. Also don't bother to complain about relative paths, which
    // don't start with /.
    wcstring_list_t existing_values;
    const auto existing_variable = vars.get(key, ENV_DEFAULT);
    if (!existing_variable.missing_or_empty()) existing_variable->to_list(existing_values);

    for (const wcstring &dir : list) {
        if (!string_prefixes_string(L"/", dir) || contains(existing_values, dir)) {
            any_success = true;
            continue;
        }

        const wchar_t *colon = std::wcschr(dir.c_str(), L':');
        bool looks_like_colon_sep = colon && colon[1];
        if (!looks_like_colon_sep && any_success) {
            // Once we have one valid entry, skip the remaining ones unless we might warn.
            continue;
        }
        struct stat buff;
        bool valid = true;
        if (wstat(dir, &buff) == -1) {
            valid = false;
        } else if (!S_ISDIR(buff.st_mode)) {
            errno = ENOTDIR;
            valid = false;
        } else if (waccess(dir, X_OK) == -1) {
            valid = false;
        }
        if (valid) {
            any_success = true;
        } else if (looks_like_colon_sep) {
            streams.err.append_format(BUILTIN_SET_PATH_ERROR, cmd, key, dir.c_str(),
                                      std::strerror(errno));
            streams.err.append_format(BUILTIN_SET_PATH_HINT, cmd, key, key,
                                      std::wcschr(dir.c_str(), L':') + 1);
        }
    }
    return any_success;
}
Exemple #23
0
static int update_values(wcstring_list_t &list, std::vector<long> &indexes,
                         wcstring_list_t &values) {
    // Replace values where needed.
    for (size_t i = 0; i < indexes.size(); i++) {
        // The '- 1' below is because the indices in fish are one-based, but the vector uses
        // zero-based indices.
        long ind = indexes[i] - 1;
        const wcstring newv = values[i];
        if (ind < 0) {
            return 1;
        }
        if ((size_t)ind >= list.size()) {
            list.resize(ind + 1);
        }

        list[ind] = newv;
    }

    return 0;
}
/// Silly function.
static void builtin_complete_add2(const wchar_t *cmd, int cmd_type, const wchar_t *short_opt,
                                  const wcstring_list_t &gnu_opt, const wcstring_list_t &old_opt,
                                  int result_mode, const wchar_t *condition, const wchar_t *comp,
                                  const wchar_t *desc, int flags) {
    size_t i;
    const wchar_t *s;

    for (s = short_opt; *s; s++) {
        complete_add(cmd, cmd_type, wcstring(1, *s), option_type_short, result_mode, condition,
                     comp, desc, flags);
    }

    for (i = 0; i < gnu_opt.size(); i++) {
        complete_add(cmd, cmd_type, gnu_opt.at(i), option_type_double_long, result_mode, condition,
                     comp, desc, flags);
    }

    for (i = 0; i < old_opt.size(); i++) {
        complete_add(cmd, cmd_type, old_opt.at(i), option_type_single_long, result_mode, condition,
                     comp, desc, flags);
    }

    if (old_opt.empty() && gnu_opt.empty() && wcslen(short_opt) == 0) {
        complete_add(cmd, cmd_type, wcstring(), option_type_args_only, result_mode, condition, comp,
                     desc, flags);
    }
}
Exemple #25
0
void parse_util_set_argv( const wchar_t * const *argv, const wcstring_list_t &named_arguments )
{
	if( *argv )
	{
		const wchar_t * const *arg;
		wcstring sb;
		
		for( arg=argv; *arg; arg++ )
		{
			if( arg != argv )
			{
				sb.append(ARRAY_SEP_STR);
			}
            sb.append(*arg);
		}
			
		env_set( L"argv", sb.c_str(), ENV_LOCAL );
	}
	else
	{
		env_set( L"argv", 0, ENV_LOCAL );
	}				

	if( named_arguments.size() )
	{
		const wchar_t * const *arg;
		size_t i;
		
		for( i=0, arg=argv; i < named_arguments.size(); i++ )
		{
			env_set( named_arguments.at(i).c_str(), *arg, ENV_LOCAL );

			if( *arg )
				arg++;
		}
			
		
	}
	
}
bool combining_expression::evaluate(wcstring_list_t &errors)
{
    switch (token)
    {
        case test_combine_and:
        case test_combine_or:
        {
            /* One-element case */
            if (subjects.size() == 1)
                return subjects.at(0)->evaluate(errors);

            /* Evaluate our lists, remembering that AND has higher precedence than OR. We can visualize this as a sequence of OR expressions of AND expressions. */
            assert(combiners.size() + 1 == subjects.size());
            assert(! subjects.empty());

            size_t idx = 0, max = subjects.size();
            bool or_result = false;
            while (idx < max)
            {
                if (or_result)
                {
                    /* Short circuit */
                    break;
                }

                /* Evaluate a stream of AND starting at given subject index. It may only have one element.  */
                bool and_result = true;
                for (; idx < max; idx++)
                {
                    /* Evaluate it, short-circuiting */
                    and_result = and_result && subjects.at(idx)->evaluate(errors);

                    /* If the combiner at this index (which corresponding to how we combine with the next subject) is not AND, then exit the loop */
                    if (idx + 1 < max && combiners.at(idx) != test_combine_and)
                    {
                        idx++;
                        break;
                    }
                }

                /* OR it in */
                or_result = or_result || and_result;
            }
            return or_result;
        }

        default:
            errors.push_back(format_string(L"Unknown token type in %s", __func__));
            return BUILTIN_TEST_FAIL;

    }
}
bool unary_operator::evaluate(wcstring_list_t &errors)
{
    switch (token)
    {
        case test_bang:
            assert(subject.get());
            return ! subject->evaluate(errors);
        default:
            errors.push_back(format_string(L"Unknown token type in %s", __func__));
            return false;

    }
}
Exemple #28
0
/**
   Merge multiple completions with the same description to the same line
*/
static void join_completions( wcstring_list_t lst )
{
    std::map<wcstring, long> desc_table;

	for( size_t i=0; i<lst.size(); i++ )
	{
		const wchar_t *item = lst.at(i).c_str();
		const wchar_t *desc = wcschr( item, COMPLETE_SEP );
		long prev_idx;
		
		if( !desc )
			continue;
		desc++;
        prev_idx = desc_table[desc] - 1;
		if( prev_idx == -1 )
		{
            desc_table[desc] = (long)(i+1);
		}
		else
		{
			const wchar_t *old = lst.at(i).c_str();
			const wchar_t *old_end = wcschr( old, COMPLETE_SEP );
			
			if( old_end )
			{
				
                wcstring foo;
                foo.append(old, old_end - old);
                foo.push_back(COMPLETE_ITEM_SEP);
                foo.append(item);
                
                lst.at(prev_idx) = foo;
                lst.at(i).clear();
			}
			
		}
		
	}	

    /* Remove empty strings */
    lst.erase(remove(lst.begin(), lst.end(), wcstring()), lst.end());
}
Exemple #29
0
/**
   Substitute any series of whitespace with a single space character
   inside completion descriptions. Remove all whitespace from
   beginning/end of completion descriptions.
*/
static void mangle_descriptions( wcstring_list_t &lst )
{
	int skip;
	for( size_t i=0; i<lst.size(); i++ )
	{
        wcstring &next = lst.at(i);
		size_t in, out;
		skip=1;
		
        size_t next_idx = 0;
		while( next_idx < next.size() && next[next_idx] != COMPLETE_SEP )
			next_idx++;
		
		if( next_idx == next.size() )
			continue;
		
		in=out=next_idx + 1;
		
		while( in < next.size() )
		{
			if( next[in] == L' ' || next[in]==L'\t' || next[in]<32 )
			{
				if( !skip )
					next[out++]=L' ';
				skip=1;					
			}
			else
			{
				next[out++] = next[in];					
				skip=0;
			}
			in++;
		}
        next.resize(out);
	}
}
/**
  Put exported or unexported variables in a string list
*/
void env_universal_common_get_names(wcstring_list_t &lst,
                                    int show_exported,
                                    int show_unexported)
{
    env_var_table_t::const_iterator iter;
    for (iter = env_universal_var.begin(); iter != env_universal_var.end(); ++iter)
    {
        const wcstring& key = iter->first;
        const var_uni_entry_t *e = iter->second;
        if ((e->exportv && show_exported) ||
                (!e->exportv && show_unexported))
        {
            lst.push_back(key);
        }

    }

}