HelenOS sources
This source file includes following definitions.
- compl_init
- compl_match_prefix
- compl_get_next
- compl_fini
#include <stdbool.h>
#include <dirent.h>
#include <errno.h>
#include <macros.h>
#include <stdlib.h>
#include <vfs/vfs.h>
#include <str.h>
#include <adt/odict.h>
#include "scli.h"
#include "cmds/cmds.h"
#include "compl.h"
#include "exec.h"
#include "tok.h"
#include "util.h"
static errno_t compl_init(char32_t *text, size_t pos, size_t *cstart, void **state);
static errno_t compl_get_next(void *state, char **compl);
static void compl_fini(void *state);
tinput_compl_ops_t compl_ops = {
.init = compl_init,
.get_next = compl_get_next,
.fini = compl_fini
};
typedef struct {
char *prefix;
size_t prefix_len;
odlink_t *alias_link;
module_t *module;
builtin_t *builtin;
const char *const *path;
char **path_list;
DIR *dir;
char *last_compl;
bool is_command;
} compl_t;
static errno_t compl_init(char32_t *text, size_t pos, size_t *cstart, void **state)
{
compl_t *cs = NULL;
char *stext = NULL;
char *prefix = NULL;
char *dirname = NULL;
errno_t retval;
token_t *tokens = calloc(WORD_MAX, sizeof(token_t));
if (tokens == NULL) {
retval = ENOMEM;
goto error;
}
size_t pref_size;
char *rpath_sep;
static const char *dirlist_arg[] = { ".", NULL };
tokenizer_t tok;
ssize_t current_token;
size_t tokens_length;
cs = calloc(1, sizeof(compl_t));
if (!cs) {
retval = ENOMEM;
goto error;
}
stext = wstr_to_astr(text);
if (stext == NULL) {
retval = ENOMEM;
goto error;
}
retval = tok_init(&tok, stext, tokens, WORD_MAX);
if (retval != EOK) {
goto error;
}
retval = tok_tokenize(&tok, &tokens_length);
if (retval != EOK) {
goto error;
}
for (current_token = 0; current_token < (ssize_t) tokens_length;
current_token++) {
token_t *t = &tokens[current_token];
size_t end = t->char_start + t->char_length;
if (t->char_start <= pos && pos <= end) {
break;
}
}
if (tokens_length == 0)
current_token = -1;
if ((current_token >= 0) && (tokens[current_token].type != TOKTYPE_SPACE))
*cstart = tokens[current_token].char_start;
else
*cstart = pos;
pref_size = str_lsize(stext, pos - *cstart);
prefix = malloc(pref_size + 1);
if (prefix == NULL) {
retval = ENOMEM;
goto error;
}
prefix[pref_size] = 0;
if (current_token >= 0) {
str_ncpy(prefix, pref_size + 1, stext +
tokens[current_token].byte_start, pref_size);
}
ssize_t prev_token = current_token - 1;
if ((prev_token >= 0) && (tokens[prev_token].type == TOKTYPE_SPACE))
prev_token--;
if ((prev_token < 0) || (tokens[prev_token].type == TOKTYPE_SPACE))
cs->is_command = true;
else
cs->is_command = false;
rpath_sep = str_rchr(prefix, '/');
if (rpath_sep != NULL) {
dirname = str_ndup(prefix, max(1, rpath_sep - prefix));
if (dirname == NULL) {
retval = ENOMEM;
goto error;
}
cs->prefix = str_dup(rpath_sep + 1);
if (cs->prefix == NULL) {
retval = ENOMEM;
goto error;
}
*cstart += rpath_sep + 1 - prefix;
cs->path_list = malloc(sizeof(char *) * 2);
if (cs->path_list == NULL) {
retval = ENOMEM;
goto error;
}
if (!is_path(prefix) && cs->is_command) {
cs->path_list[0] = malloc(sizeof(char) * PATH_MAX);
if (cs->path_list[0] == NULL) {
retval = ENOMEM;
goto error;
}
int ret = snprintf(cs->path_list[0], PATH_MAX, "%s/%s", search_dir[0], dirname);
if (ret < 0 || ret >= PATH_MAX) {
retval = ENOMEM;
goto error;
}
} else {
cs->path_list[0] = dirname;
}
free(prefix);
cs->path_list[1] = NULL;
cs->path = (const char *const *) cs->path_list;
} else if (cs->is_command) {
cs->alias_link = odict_first(&alias_dict);
cs->module = modules;
cs->builtin = builtins;
cs->prefix = prefix;
cs->path = &search_dir[0];
} else {
cs->prefix = prefix;
cs->path = &dirlist_arg[0];
}
cs->prefix_len = str_length(cs->prefix);
tok_fini(&tok);
*state = cs;
return EOK;
error:
tok_fini(&tok);
if (cs != NULL && cs->path_list != NULL) {
size_t i = 0;
while (cs->path_list[i] != NULL) {
free(cs->path_list[i]);
++i;
}
free(cs->path_list);
}
if ((cs != NULL) && (cs->prefix != NULL))
free(cs->prefix);
if (dirname != NULL)
free(dirname);
if (prefix != NULL)
free(prefix);
if (stext != NULL)
free(stext);
if (cs != NULL)
free(cs);
if (tokens != NULL)
free(tokens);
return retval;
}
static bool compl_match_prefix(compl_t *cs, const char *compl)
{
return str_lcmp(compl, cs->prefix, cs->prefix_len) == 0;
}
static errno_t compl_get_next(void *state, char **compl)
{
compl_t *cs = (compl_t *) state;
struct dirent *dent;
*compl = NULL;
if (cs->last_compl != NULL) {
free(cs->last_compl);
cs->last_compl = NULL;
}
if (cs->alias_link != NULL) {
while (*compl == NULL && cs->alias_link != NULL) {
alias_t *data = odict_get_instance(cs->alias_link, alias_t, odict);
if (compl_match_prefix(cs, data->name)) {
asprintf(compl, "%s ", data->name);
cs->last_compl = *compl;
if (*compl == NULL)
return ENOMEM;
}
cs->alias_link = odict_next(cs->alias_link, &alias_dict);
}
}
if (cs->module != NULL) {
while (*compl == NULL && cs->module->name != NULL) {
if (compl_match_prefix(cs, cs->module->name)) {
odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)cs->module->name, NULL);
if (alias_link == NULL) {
asprintf(compl, "%s ", cs->module->name);
cs->last_compl = *compl;
if (*compl == NULL)
return ENOMEM;
}
}
cs->module++;
}
}
if (cs->builtin != NULL) {
while (*compl == NULL && cs->builtin->name != NULL) {
if (compl_match_prefix(cs, cs->builtin->name)) {
odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)cs->module->name, NULL);
if (alias_link == NULL) {
asprintf(compl, "%s ", cs->builtin->name);
cs->last_compl = *compl;
if (*compl == NULL)
return ENOMEM;
}
}
cs->builtin++;
}
}
if (cs->path != NULL) {
while (*compl == NULL) {
while (cs->dir == NULL) {
if (*cs->path == NULL)
break;
cs->dir = opendir(*cs->path);
if (cs->dir == NULL)
cs->path++;
}
if (cs->dir == NULL)
break;
dent = readdir(cs->dir);
if (dent == NULL) {
closedir(cs->dir);
cs->dir = NULL;
cs->path++;
continue;
}
if (compl_match_prefix(cs, dent->d_name)) {
char *ent_path;
asprintf(&ent_path, "%s/%s", *cs->path, dent->d_name);
vfs_stat_t ent_stat;
if (vfs_stat_path(ent_path, &ent_stat) != EOK) {
free(ent_path);
continue;
}
free(ent_path);
if (cs->is_command && !ent_stat.is_directory) {
odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)dent->d_name, NULL);
if (alias_link != NULL) {
continue;
}
}
asprintf(compl, "%s%c", dent->d_name,
ent_stat.is_directory ? '/' : ' ');
cs->last_compl = *compl;
if (*compl == NULL)
return ENOMEM;
}
}
}
if (*compl == NULL)
return ENOENT;
return EOK;
}
static void compl_fini(void *state)
{
compl_t *cs = (compl_t *) state;
if (cs->path_list != NULL) {
size_t i = 0;
while (cs->path_list[i] != NULL) {
free(cs->path_list[i]);
++i;
}
free(cs->path_list);
}
if (cs->last_compl != NULL)
free(cs->last_compl);
if (cs->dir != NULL)
closedir(cs->dir);
free(cs->prefix);
free(cs);
}
HelenOS homepage, sources at GitHub