196 lines
4.3 KiB
C
196 lines
4.3 KiB
C
#include "../include/complete.h"
|
|
#include "../include/shell.h"
|
|
#include "../include/tree.h"
|
|
#include "../include/utils.h"
|
|
|
|
/**
|
|
* @brief Checks if file located at specified path is executable
|
|
*
|
|
* @param path
|
|
* @param file_name
|
|
* @return true
|
|
* @return false
|
|
*/
|
|
bool check_if_executable(char *path, char *file_name)
|
|
{
|
|
char *file_path = malloc(strlen(path) + strlen(file_name) + 2);
|
|
file_path[0] = '\0';
|
|
file_path = strcat(file_path, path);
|
|
file_path = strcat(file_path, "/");
|
|
file_path = strcat(file_path, file_name);
|
|
|
|
bool ret = access(file_path, X_OK) == 0;
|
|
free(file_path);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the list of files and directories at the specified path
|
|
*
|
|
* @param dir_list
|
|
* @param path
|
|
* @param ex
|
|
* @return ssize_t
|
|
*/
|
|
ssize_t get_dir_list(char ***dir_list, char *path, int ex)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *ent;
|
|
|
|
if ((dir = opendir(path)) == NULL)
|
|
{
|
|
perror("\nOpendir");
|
|
return -1;
|
|
}
|
|
|
|
ssize_t n = 0;
|
|
while ((ent = readdir(dir)) != NULL)
|
|
{
|
|
if (ex != 0 && !check_if_executable(path, ent->d_name))
|
|
continue;
|
|
|
|
n++;
|
|
*dir_list = realloc(*dir_list, sizeof(char *) * n);
|
|
(*dir_list)[n - 1] = strdup(ent->d_name);
|
|
|
|
if (ent->d_type == DT_DIR)
|
|
{
|
|
(*dir_list)[n - 1] = realloc((*dir_list)[n - 1], strlen((*dir_list)[n - 1]) + 2);
|
|
(*dir_list)[n - 1] = strcat((*dir_list)[n - 1], "/");
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
* @brief Append builtin commands to the completions list
|
|
*
|
|
* @param commands_list
|
|
* @param size
|
|
* @return ssize_t
|
|
*/
|
|
ssize_t append_builtin_list(char ***commands_list, size_t *size)
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
(*size)++;
|
|
*commands_list = realloc(*commands_list, sizeof(char *) * *size);
|
|
(*commands_list)[*size - 1] = strdup(builtin[i]);
|
|
}
|
|
|
|
return *size;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the complete options based on user input
|
|
*
|
|
* @param opts
|
|
* @param line
|
|
* @param to_complete
|
|
* @return ssize_t
|
|
*/
|
|
ssize_t get_complete_options(char ***opts, char *line, char **to_complete)
|
|
{
|
|
char **args = NULL, **folders = malloc(0);
|
|
ssize_t sz;
|
|
|
|
int am = sep_string(line, &args, " ");
|
|
|
|
char *last_arg = args[am - 1];
|
|
|
|
if (am > 0)
|
|
{
|
|
int path_depth = sep_string(last_arg, &folders, "/");
|
|
*to_complete = strdup(folders[path_depth - 1]);
|
|
|
|
char *curr_pos = NULL;
|
|
int i = 0;
|
|
|
|
if (last_arg[0] == '/')
|
|
{
|
|
curr_pos = strdup("");
|
|
}
|
|
else if (strchr(line, ' '))
|
|
{
|
|
curr_pos = strdup(".");
|
|
}
|
|
else if (last_arg[0] == '.' && last_arg[1] == '/')
|
|
{
|
|
curr_pos = strdup(folders[0]);
|
|
i++;
|
|
}
|
|
else
|
|
goto ABSOLUTE;
|
|
|
|
for (int i = 0; i < (path_depth - 1); i++)
|
|
{
|
|
curr_pos = realloc(curr_pos, strlen(curr_pos) + strlen(folders[i]) + 2);
|
|
curr_pos = strcat(curr_pos, "/");
|
|
curr_pos = strcat(curr_pos, folders[i]);
|
|
}
|
|
sz = get_dir_list(opts, curr_pos, 0);
|
|
|
|
free(curr_pos);
|
|
}
|
|
else
|
|
{
|
|
ABSOLUTE:
|
|
*to_complete = strdup(line);
|
|
sz = get_dir_list(opts, "/usr/bin", 1);
|
|
|
|
append_builtin_list(opts, &sz);
|
|
}
|
|
|
|
free_str_arr(args);
|
|
free_str_arr(folders);
|
|
|
|
if (sz < 0)
|
|
return sz;
|
|
|
|
if ((*to_complete)[0] != '\0')
|
|
{
|
|
sz = filter_options(opts, &sz, *to_complete);
|
|
}
|
|
|
|
return sz;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets completing options which begins with user input
|
|
*
|
|
* @param comp_list
|
|
* @param size
|
|
* @param filter_string
|
|
* @return ssize_t
|
|
*/
|
|
ssize_t filter_options(char ***comp_list, ssize_t *size, char *filter_string)
|
|
{
|
|
if (*size < 0)
|
|
return *size;
|
|
|
|
struct tree_node *child_dirs_root = get_new_node();
|
|
for (ssize_t i = 0; i < *size; i++)
|
|
insert_tree(child_dirs_root, (*comp_list)[i]);
|
|
|
|
char **folders = NULL;
|
|
int path_depth = sep_string(filter_string, &folders, "/");
|
|
|
|
char *last_option = strdup(filter_string);
|
|
|
|
if (path_depth > 0)
|
|
{
|
|
free(last_option);
|
|
last_option = folders[path_depth - 1];
|
|
}
|
|
|
|
*size = list_strings_containing(child_dirs_root, last_option, comp_list);
|
|
|
|
free_tree(child_dirs_root);
|
|
free_str_arr(folders);
|
|
|
|
return *size;
|
|
} |