예제 #1
0
static char *
username_completion_function (const char *text, int state, input_complete_t flags)
{
    static struct passwd *entry;
    static size_t userlen;

    (void) flags;
    SHOW_C_CTX ("username_completion_function");

    if (text[0] == '\\' && text[1] == '~')
        text++;
    if (state == 0)
    {                           /* Initialization stuff */
        setpwent ();
        userlen = strlen (text + 1);
    }
    while ((entry = getpwent ()) != NULL)
    {
        /* Null usernames should result in all users as possible completions. */
        if (userlen == 0)
            break;
        if (text[1] == entry->pw_name[0] && !strncmp (text + 1, entry->pw_name, userlen))
            break;
    }

    if (entry != NULL)
        return g_strconcat ("~", entry->pw_name, PATH_SEP_STR, (char *) NULL);

    endpwent ();
    return NULL;
}
예제 #2
0
static char *
hostname_completion_function (const char *text, int state, input_complete_t flags)
{
    static char **host_p;
    static int textstart, textlen;

    (void) flags;
    SHOW_C_CTX ("hostname_completion_function");

    if (!state)
    {                           /* Initialization stuff */
        const char *p;

        if (hosts != NULL)
        {
            for (host_p = hosts; *host_p; host_p++)
                g_free (*host_p);
            g_free (hosts);
        }
        hosts = g_new (char *, (hosts_alloclen = 30) + 1);
        *hosts = NULL;
        hosts_p = hosts;
        fetch_hosts ((p = getenv ("HOSTFILE")) ? p : "/etc/hosts");
        host_p = hosts;
        textstart = (*text == '@') ? 1 : 0;
        textlen = strlen (text + textstart);
    }

    while (*host_p)
    {
        if (!textlen)
            break;              /* Match all of them */
        else if (!strncmp (text + textstart, *host_p, textlen))
            break;
        host_p++;
    }

    if (!*host_p)
    {
        for (host_p = hosts; *host_p; host_p++)
            g_free (*host_p);
        g_free (hosts);
        hosts = NULL;
        return NULL;
    }
    else
    {
        char *temp = g_malloc (2 + strlen (*host_p));

        if (textstart)
            *temp = '@';
        strcpy (temp + textstart, *host_p);
        host_p++;
        return temp;
    }
}
예제 #3
0
static char *
variable_completion_function (const char *text, int state, input_complete_t flags)
{
    static char **env_p;
    static unsigned int isbrace;
    static size_t varlen;
    const char *p = NULL;

    (void) flags;
    SHOW_C_CTX ("variable_completion_function");

    if (state == 0)
    {                           /* Initialization stuff */
        isbrace = (text[1] == '{') ? 1 : 0;
        varlen = strlen (text + 1 + isbrace);
        env_p = environ;
    }

    while (*env_p)
    {
        p = strchr (*env_p, '=');
        if (p && ((size_t) (p - *env_p) >= varlen) && !strncmp (text + 1 + isbrace, *env_p, varlen))
            break;
        env_p++;
    }

    if (*env_p == NULL)
        return NULL;

    {
        GString *temp;

        temp = g_string_new_len (*env_p, p - *env_p);

        if (isbrace != 0)
        {
            g_string_prepend_c (temp, '{');
            g_string_append_c (temp, '}');
        }
        g_string_prepend_c (temp, '$');

        env_p++;

        return g_string_free (temp, FALSE);
    }
}
예제 #4
0
/** Check if directory completion is needed */
static gboolean
check_is_cd (const char *text, int lc_start, input_complete_t flags)
{
    char *p, *q;

    SHOW_C_CTX ("check_is_cd");

    if ((flags & INPUT_COMPLETE_CD) == 0)
        return FALSE;

    /* Skip initial spaces */
    p = (char *) text;
    q = (char *) text + lc_start;
    while (p < q && p[0] != '\0' && str_isspace (p))
        str_next_char (&p);

    /* Check if the command is "cd" and the cursor is after it */
    return (p[0] == 'c' && p[1] == 'd' && str_isspace (p + 2) && p + 2 < q);
}
예제 #5
0
static char *
variable_completion_function (const char *text, int state, input_complete_t flags)
{
    static char **env_p;
    static int varlen, isbrace;
    const char *p = NULL;

    (void) flags;
    SHOW_C_CTX ("variable_completion_function");

    if (state == 0)
    {                           /* Initialization stuff */
        isbrace = (text[1] == '{');
        varlen = strlen (text + 1 + isbrace);
        env_p = environ;
    }

    while (*env_p)
    {
        p = strchr (*env_p, '=');
        if (p && p - *env_p >= varlen && !strncmp (text + 1 + isbrace, *env_p, varlen))
            break;
        env_p++;
    }

    if (*env_p == NULL)
        return NULL;

    {
        char *temp = g_malloc (2 + 2 * isbrace + p - *env_p);

        *temp = '$';
        if (isbrace)
            temp[1] = '{';
        memcpy (temp + 1 + isbrace, *env_p, p - *env_p);
        if (isbrace)
            strcpy (temp + 2 + (p - *env_p), "}");
        else
            temp[1 + p - *env_p] = 0;
        env_p++;
        return temp;
    }
}
예제 #6
0
static char *
filename_completion_function (const char *text, int state, input_complete_t flags)
{
    static DIR *directory = NULL;
    static char *filename = NULL;
    static char *dirname = NULL;
    static char *users_dirname = NULL;
    static size_t filename_len;
    int isdir = 1, isexec = 0;
    static vfs_path_t *dirname_vpath = NULL;

    struct dirent *entry = NULL;

    SHOW_C_CTX ("filename_completion_function");

    if (text && (flags & INPUT_COMPLETE_SHELL_ESC))
    {
        char *u_text;
        char *result;
        char *e_result;

        u_text = strutils_shell_unescape (text);

        result = filename_completion_function (u_text, state, flags & (~INPUT_COMPLETE_SHELL_ESC));
        g_free (u_text);

        e_result = strutils_shell_escape (result);
        g_free (result);

        return e_result;
    }

    /* If we're starting the match process, initialize us a bit. */
    if (state == 0)
    {
        const char *temp;

        g_free (dirname);
        g_free (filename);
        g_free (users_dirname);
        vfs_path_free (dirname_vpath);

        if ((*text != '\0') && (temp = strrchr (text, PATH_SEP)) != NULL)
        {
            filename = g_strdup (++temp);
            dirname = g_strndup (text, temp - text);
        }
        else
        {
            dirname = g_strdup (".");
            filename = g_strdup (text);
        }

        /* We aren't done yet.  We also support the "~user" syntax. */

        /* Save the version of the directory that the user typed. */
        users_dirname = dirname;
        dirname = tilde_expand (dirname);
        canonicalize_pathname (dirname);
        dirname_vpath = vfs_path_from_str (dirname);

        /* Here we should do something with variable expansion
           and `command`.
           Maybe a dream - UNIMPLEMENTED yet. */

        directory = mc_opendir (dirname_vpath);
        filename_len = strlen (filename);
    }

    /* Now that we have some state, we can read the directory. */

    while (directory && (entry = mc_readdir (directory)))
    {
        if (!str_is_valid_string (entry->d_name))
            continue;

        /* Special case for no filename.
           All entries except "." and ".." match. */
        if (filename_len == 0)
        {
            if (DIR_IS_DOT (entry->d_name) || DIR_IS_DOTDOT (entry->d_name))
                continue;
        }
        else
        {
            /* Otherwise, if these match up to the length of filename, then
               it may be a match. */
            if ((entry->d_name[0] != filename[0]) ||
                ((NLENGTH (entry)) < filename_len) ||
                strncmp (filename, entry->d_name, filename_len))
                continue;
        }
        isdir = 1;
        isexec = 0;
        {
            struct stat tempstat;
            vfs_path_t *tmp_vpath;

            tmp_vpath = vfs_path_build_filename (dirname, entry->d_name, (char *) NULL);

            /* Unix version */
            if (mc_stat (tmp_vpath, &tempstat) == 0)
            {
                uid_t my_uid = getuid ();
                gid_t my_gid = getgid ();

                if (!S_ISDIR (tempstat.st_mode))
                {
                    isdir = 0;
                    if ((!my_uid && (tempstat.st_mode & 0111)) ||
                        (my_uid == tempstat.st_uid && (tempstat.st_mode & 0100)) ||
                        (my_gid == tempstat.st_gid && (tempstat.st_mode & 0010)) ||
                        (tempstat.st_mode & 0001))
                        isexec = 1;
                }
            }
            else
            {
                /* stat failed, strange. not a dir in any case */
                isdir = 0;
            }
            vfs_path_free (tmp_vpath);
        }
        if ((flags & INPUT_COMPLETE_COMMANDS) && (isexec || isdir))
            break;
        if ((flags & INPUT_COMPLETE_CD) && isdir)
            break;
        if (flags & (INPUT_COMPLETE_FILENAMES))
            break;
    }

    if (entry == NULL)
    {
        if (directory)
        {
            mc_closedir (directory);
            directory = NULL;
        }
        g_free (dirname);
        dirname = NULL;
        vfs_path_free (dirname_vpath);
        dirname_vpath = NULL;
        g_free (filename);
        filename = NULL;
        g_free (users_dirname);
        users_dirname = NULL;
        return NULL;
    }

    {
        GString *temp;

        temp = g_string_sized_new (16);

        if (users_dirname != NULL && (users_dirname[0] != '.' || users_dirname[1] != '\0'))
        {
            g_string_append (temp, users_dirname);

            /* We need a '/' at the end. */
            if (temp->str[temp->len - 1] != PATH_SEP)
                g_string_append_c (temp, PATH_SEP);
        }
        g_string_append (temp, entry->d_name);
        if (isdir)
            g_string_append_c (temp, PATH_SEP);

        return g_string_free (temp, FALSE);
    }
}
예제 #7
0
static char *
command_completion_function (const char *_text, int state, input_complete_t flags)
{
    char *text;
    static const char *path_end;
    static gboolean isabsolute;
    static int phase;
    static size_t text_len;
    static const char *const *words;
    static char *path;
    static char *cur_path;
    static char *cur_word;
    static int init_state;
    static const char *const bash_reserved[] = {
        "if", "then", "else", "elif", "fi", "case", "esac", "for",
        "select", "while", "until", "do", "done", "in", "function", 0
    };
    static const char *const bash_builtins[] = {
        "alias", "bg", "bind", "break", "builtin", "cd", "command",
        "continue", "declare", "dirs", "echo", "enable", "eval",
        "exec", "exit", "export", "fc", "fg", "getopts", "hash",
        "help", "history", "jobs", "kill", "let", "local", "logout",
        "popd", "pushd", "pwd", "read", "readonly", "return", "set",
        "shift", "source", "suspend", "test", "times", "trap", "type",
        "typeset", "ulimit", "umask", "unalias", "unset", "wait", 0
    };
    char *p, *found;

    SHOW_C_CTX ("command_completion_function");

    if (!(flags & INPUT_COMPLETE_COMMANDS))
        return 0;

    text = strutils_shell_unescape (_text);
    flags &= ~INPUT_COMPLETE_SHELL_ESC;

    if (state == 0)
    {                           /* Initialize us a little bit */
        isabsolute = strchr (text, PATH_SEP) != NULL;
        if (!isabsolute)
        {
            words = bash_reserved;
            phase = 0;
            text_len = strlen (text);

            if (path == NULL)
            {
                path = g_strdup (getenv ("PATH"));
                if (path != NULL)
                {
                    p = path;
                    path_end = strchr (p, '\0');
                    while ((p = strchr (p, PATH_ENV_SEP)) != NULL)
                    {
                        *p++ = '\0';
                    }
                }
            }
        }
    }

    if (isabsolute)
    {
        p = filename_completion_function (text, state, flags);

        if (p != NULL)
        {
            char *temp_p = p;
            p = strutils_shell_escape (p);
            g_free (temp_p);
        }

        g_free (text);
        return p;
    }

    found = NULL;
    switch (phase)
    {
    case 0:                    /* Reserved words */
        while (*words)
        {
            if (strncmp (*words, text, text_len) == 0)
            {
                g_free (text);
                return g_strdup (*(words++));
            }
            words++;
        }
        phase++;
        words = bash_builtins;
    case 1:                    /* Builtin commands */
        while (*words)
        {
            if (strncmp (*words, text, text_len) == 0)
            {
                g_free (text);
                return g_strdup (*(words++));
            }
            words++;
        }
        phase++;
        if (!path)
            break;
        cur_path = path;
        cur_word = NULL;
    case 2:                    /* And looking through the $PATH */
        while (!found)
        {
            if (!cur_word)
            {
                char *expanded;

                if (cur_path >= path_end)
                    break;
                expanded = tilde_expand (*cur_path ? cur_path : ".");
                cur_word = mc_build_filename (expanded, text, NULL);
                g_free (expanded);
                canonicalize_pathname (cur_word);
                cur_path = strchr (cur_path, 0) + 1;
                init_state = state;
            }
            found = filename_completion_function (cur_word, state - init_state, flags);
            if (!found)
            {
                g_free (cur_word);
                cur_word = NULL;
            }
        }
    }

    if (found == NULL)
    {
        g_free (path);
        path = NULL;
    }
    else
    {
        p = strrchr (found, PATH_SEP);
        if (p != NULL)
        {
            char *tmp = found;
            found = strutils_shell_escape (p + 1);
            g_free (tmp);
        }
    }

    g_free (text);
    return found;
}