/// The builtin builtin, used for giving builtins precedence over functions. Mostly handled by the
/// parser. All this code does is some additional operational modes, such as printing a list of all
/// builtins, printing help, etc.
int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    builtin_cmd_opts_t opts;

    int optind;
    int retval = parse_cmd_opts(opts, &optind, argc, argv, parser, streams);
    if (retval != STATUS_CMD_OK) return retval;

    if (opts.print_help) {
        builtin_print_help(parser, streams, cmd, streams.out);
        return STATUS_CMD_OK;
    }

    if (opts.query && opts.list_names) {
        streams.err.append_format(BUILTIN_ERR_COMBO2, cmd,
                                  _(L"--query and --names are mutually exclusive"));
        return STATUS_INVALID_ARGS;
    }

    if (opts.query) {
        wcstring_list_t names = builtin_get_names();
        retval = STATUS_CMD_ERROR;
        for (int i = optind; i < argc; i++) {
            if (contains(names, argv[i])) {
                retval = STATUS_CMD_OK;
                break;
            }
        }
        return retval;
    }

    if (opts.list_names) {
        wcstring_list_t names = builtin_get_names();
        std::sort(names.begin(), names.end());

        for (size_t i = 0; i < names.size(); i++) {
            const wchar_t *el = names.at(i).c_str();

            streams.out.append(el);
            streams.out.append(L"\n");
        }
    }

    return STATUS_CMD_OK;
}
Example #2
0
/**
   Complete the specified command name. Search for executables in the
   path, executables defined using an absolute path, functions,
   builtins and directories for implicit cd commands.

   \param cmd the command string to find completions for

   \param comp the list to add all completions to
*/
static void complete_cmd( const wchar_t *cmd,
						  array_list_t *comp,
						  int use_function,
						  int use_builtin,
						  int use_command )
{
	wchar_t *path;
	wchar_t *path_cpy;
	wchar_t *nxt_path;
	wchar_t *state;
	array_list_t possible_comp;
	wchar_t *nxt_completion;

	wchar_t *cdpath = env_get(L"CDPATH");
	wchar_t *cdpath_cpy = wcsdup( cdpath?cdpath:L"." );

	if( (wcschr( cmd, L'/') != 0) || (cmd[0] == L'~' ) )
	{

		if( use_command )
		{

			if( expand_string( 0,
							   wcsdup(cmd),
							   comp,
							   ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
			{
				complete_cmd_desc( cmd, comp );
			}
		}
	}
	else
	{
		if( use_command )
		{

			path = env_get(L"PATH");
			if( path )
			{

				path_cpy = wcsdup( path );

				for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
				     nxt_path != 0;
				     nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
				{
					int prev_count;
					int i;
					int path_len = wcslen(nxt_path);
					int add_slash;

					if( !path_len )
					{
						continue;
					}

					add_slash = nxt_path[path_len-1]!=L'/';
					nxt_completion = wcsdupcat( nxt_path,
												add_slash?L"/":L"",
												cmd );
					if( ! nxt_completion )
						continue;

					prev_count = al_get_count( comp );

					if( expand_string( 0,
									   nxt_completion,
									   comp,
									   ACCEPT_INCOMPLETE |
									   EXECUTABLES_ONLY ) != EXPAND_ERROR )
					{
						for( i=prev_count; i<al_get_count( comp ); i++ )
						{
							completion_t *c = (completion_t *)al_get( comp, i );
							if(c->flags & COMPLETE_NO_CASE )
							{
								c->completion = halloc_wcsdup( comp, c->completion + path_len + add_slash );
							}
						}
					}
				}
				free( path_cpy );
				complete_cmd_desc( cmd, comp );
			}
		}

		/*
		  These return the original strings - don't free them
		*/

		al_init( &possible_comp );

		if( use_function )
		{
			function_get_names( &possible_comp, cmd[0] == L'_' );
			complete_strings( comp, cmd, 0, &complete_function_desc, &possible_comp, 0 );
		}

		al_truncate( &possible_comp, 0 );

		if( use_builtin )
		{
			builtin_get_names( &possible_comp );
			complete_strings( comp, cmd, 0, &builtin_get_desc, &possible_comp, 0 );
		}
		al_destroy( &possible_comp );

	}

	if( use_builtin || (use_function && function_exists( L"cd") ) )
	{
		/*
		  Tab complete implicit cd for directories in CDPATH
		*/
		if( cmd[0] != L'/' && ( wcsncmp( cmd, L"./", 2 )!=0) )
		{
			for( nxt_path = wcstok( cdpath_cpy, ARRAY_SEP_STR, &state );
				 nxt_path != 0;
				 nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
			{
				wchar_t *nxt_completion=
					wcsdupcat( nxt_path,
							   (nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
							   cmd );
				if( ! nxt_completion )
				{
					continue;
				}

				if( expand_string( 0,
								   nxt_completion,
								   comp,
								   ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR )
				{
				}
			}
		}
	}

	free( cdpath_cpy );
}